Skip to content

fix(agent-script): prevent Object globals from mutating host prototypes#315

Open
kamilio wants to merge 1 commit into
mainfrom
codex/fix-host-prototype-pollution-vulnerability
Open

fix(agent-script): prevent Object globals from mutating host prototypes#315
kamilio wants to merge 1 commit into
mainfrom
codex/fix-host-prototype-pollution-vulnerability

Conversation

@kamilio
Copy link
Copy Markdown
Collaborator

@kamilio kamilio commented May 15, 2026

Motivation

  • Prevent sandboxed scripts from reaching and mutating host prototypes (for example Object.prototype) via the newly exposed Object.assign/Object.freeze globals, which cross the sandbox boundary and enable prototype pollution or process-wide DoS.

Description

  • Route the Object.freeze global through a guarded helper freezeSandboxValue so freezing is only applied to approved sandbox-owned targets and is a no-op for other values.
  • Tighten target validation with isAssignableSandboxTarget so only arrays or plain objects whose prototype is Object.prototype (and that are not sandbox closures/promises) are considered assignable.
  • Keep Object.assign semantics but reject non-assignable targets with a TypeError to prevent writes to host prototype objects.
  • Add a regression test that asserts Object.assign(Object.prototype, ...) is rejected and Object.freeze(Object.prototype) is a no-op that does not freeze the host prototype.

Testing

  • Ran npm run test:unit -- packages/agent-script/src/interp/globals/object-array.test.ts and all tests passed (5 passed).
  • Pre-commit checks (npm run lint:eslint and tsc -p tsconfig.build.json --noEmit) ran as part of the commit hook; lint produced warnings only and type check passed.

Codex Task

Copy link
Copy Markdown
Contributor

@poe-code-agent poe-code-agent Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Requested changes: Object.assign/freeze now rejects sandbox object literals.

Comment on lines +115 to +119
if (Array.isArray(value)) {
return true;
}

return Object.getPrototypeOf(value) === Object.prototype;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Object literals are created with Object.create(null) in interpreter.ts, so this now rejects ordinary script code like Object.assign({}, { ok: true }) and Object.freeze({}). I verified run('return Object.assign({}, { ok: true }).ok') now throws this TypeError. Please allow sandbox null-prototype objects while still blocking the host prototypes.

Suggested change
if (Array.isArray(value)) {
return true;
}
return Object.getPrototypeOf(value) === Object.prototype;
if (Array.isArray(value)) {
return value !== Array.prototype;
}
const prototype = Object.getPrototypeOf(value);
return prototype === Object.prototype || (prototype === null && value !== Object.prototype);

});


it("blocks assign and freeze on host prototype objects", async () => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add coverage for the sandbox object-literal/null-prototype path here too. The current test covers Object.prototype, but not {} from the interpreter, which is the regression path for Object.assign({}, source) and Object.freeze({}).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant