Skip to content

Commit b80ddc4

Browse files
committed
Reject non-JSON capability objects
1 parent 81a7a92 commit b80ddc4

3 files changed

Lines changed: 17 additions & 3 deletions

File tree

.changeset/capability-review-fixes.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ 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 and inherited-property validation bypasses, honor middleware replacement
13-
responses, and keep test-host agent context aligned with production.
12+
schemas, inherited-property validation bypasses, and non-JSON object values, honor
13+
middleware replacement responses, and keep test-host agent context aligned with
14+
production.

packages/capabilities/src/schema.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,5 +341,7 @@ function cloneJson<T>(value: T): T {
341341
}
342342

343343
function isPlainObject(value: unknown): value is Record<string, unknown> {
344-
return typeof value === "object" && value !== null && !Array.isArray(value);
344+
if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
345+
const prototype = Object.getPrototypeOf(value);
346+
return prototype === Object.prototype || prototype === null;
345347
}

packages/capabilities/test/schema.test.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,17 @@ describe("validateAgainstSchema", () => {
5555
expect(issues).toEqual([{ path: "/query", message: "must be of type string, got number" }]);
5656
});
5757

58+
it("rejects JavaScript objects outside the JSON data model", () => {
59+
class Instance {}
60+
61+
for (const value of [new Date(), new Map(), new Instance()]) {
62+
expect(validateAgainstSchema({ type: "object" }, value)).toEqual([
63+
{ path: "", message: "must be of type object, got object" },
64+
]);
65+
}
66+
expect(validateAgainstSchema({ type: "object" }, Object.create(null))).toEqual([]);
67+
});
68+
5869
it("enforces integer vs number", () => {
5970
expect(validateAgainstSchema(schema, { query: "x", limit: 1.5 })).toEqual([
6071
{ path: "/limit", message: "must be of type integer, got number" },

0 commit comments

Comments
 (0)