Skip to content

Commit 81a7a92

Browse files
committed
Reject inherited capability input properties
1 parent 46cbe29 commit 81a7a92

3 files changed

Lines changed: 14 additions & 4 deletions

File tree

.changeset/capability-review-fixes.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ Harden capability dispatch and agent trust edge cases: normalize custom HTTP
99
paths, fail closed for custom endpoints when registry resolution fails, stream
1010
agent-directory responses within the documented size cap, expose confirmation
1111
fields in browser types, preserve explicit null capability inputs, reject malformed
12-
schemas, honor middleware replacement responses, and keep test-host agent context
13-
aligned with production.
12+
schemas and inherited-property validation bypasses, honor middleware replacement
13+
responses, and keep test-host agent context aligned with production.

packages/capabilities/src/schema.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ export function validateAgainstSchema(schema: unknown, value: unknown, path = ""
264264
}
265265

266266
for (const [name, propertyValue] of Object.entries(value)) {
267-
const propertySchema = properties[name];
268-
if (propertySchema !== undefined) {
267+
if (Object.hasOwn(properties, name)) {
268+
const propertySchema = properties[name];
269269
issues.push(...validateAgainstSchema(propertySchema, propertyValue, `${path}/${name}`));
270270
continue;
271271
}

packages/capabilities/test/schema.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,16 @@ describe("validateAgainstSchema", () => {
7979
]);
8080
});
8181

82+
it("rejects prototype-named properties unless explicitly declared", () => {
83+
const closedSchema = { type: "object", properties: {}, additionalProperties: false };
84+
for (const name of ["constructor", "toString", "__proto__"]) {
85+
const input = JSON.parse(`{${JSON.stringify(name)}:1}`);
86+
expect(validateAgainstSchema(closedSchema, input)).toEqual([
87+
{ path: `/${name}`, message: "is not an allowed property" },
88+
]);
89+
}
90+
});
91+
8292
it("validates array items with indexed paths", () => {
8393
expect(validateAgainstSchema(schema, { query: "x", tags: ["ok", 7] })).toEqual([
8494
{ path: "/tags/1", message: "must be of type string, got number" },

0 commit comments

Comments
 (0)