Repository navigation
fix(kits): share the proposal policy and harden proposal scanning - #87
Merged
Merged
Conversation
Add skillx.kit-proposal-policy/v1 with the forbidden-key lists, key normalization, the refusing content rules and the local path system allowlist, plus shared vectors that SkillX and AgentKit both test against. Refs #84.
Make every proposal detector linear in its input, refuse flag-glued paths, editor file links, non-ASCII segments, /usr/home and /usr/local/<org>, find YAML password list items and quoted keys, and require a web session to activate rebase or resolution drafts that carry a session-derived revision forward. Refs #86.
A revision is gated when it or any ancestor, through any origin, is session-derived; a missing ancestor counts as gated. A gated revision activates only from a web session, on a private kit, as a private document. Activating any public document now needs a web session.
Pin the key normalization order and Unicode version, escape key paths, and match password and secret assignments through the shared key normalization. The path allowlist keeps exact well-known entries and binary or library subtrees only, and the path detector reads %2E, NFD and zero-width forms. The cost test asserts linear growth.
Check the history of every parent revision the lock lineage loads, so a kit whose document parent is a session-derived revision activates only from a web session. A new kit always starts private.
Read an assignment value in a bounded lookahead so keys inside values and after flags are found, accept := and =>, and allow up to two qualifiers after a secret stem. Read Unicode slashes, refuse escapes left after three decoding rounds, and stop URLs at more delimiters.
This was referenced Oct 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refs #84 (SkillX side; AgentKit consumption pending). Closes #86. Part of #31.
Shared proposal policy (#84)
skillx.kit-proposal-policy/v1inpackages/contracts/src/fixtures/kit-proposal-policy-v1.json. It holds:exactandcontainslists;A-Z, strip non-[a-z0-9];content.secretKeys(password and secret stems for content assignments);exactentries andsubtrees.kit-proposal-policy-vectors-v1.json, covering:@skillx/contractsexportsnormalizeProposalKey,isForbiddenProposalKey,findForbiddenProposalKeyandsecretKeyKind. Key paths escape.and[(proposal["a.b"]), and a key over the limit is reported as[…]. The web envelope now uses them in place of its local list.Scan hardening (#86)
-I/opt/x,-isystem/...,--include=/...);vscode://file/...and other editor file links;/Usuários/...);/usr/homeand/usr/local/<org>.-I/usr/include;/usr/localsystem directories;https,ssh,s3, ...).- password:) and quoted keys ("password":).SKILLX_SHARED_SKILL_ALIASESfrom it. There is no code change.SKILLX_PERSONAL_KITS_APIstays"0". No migration.Round-1 review decisions
proposal.private_kit_required).publicdocument needs a web session, whatever its origin (403kit.interactive_approval_required). Gated revisions stay private-only./usr/src,/proc/self/root,/proc/*/rootand/proc/*/cwdare refused./usr/share,/usr/local/{share,etc,opt}and/etcallow only exact well-known entries, not subtrees. Vectors for each.dbPassword,clientSecret,apiKey,accessTokenand similar in YAML, JSON,.envand codekey: value/key = valueare refused (secret-password, newsecret-assignment,secret-dotenv), matched through the shared key normalization so content rules and envelope keys agree. Vectors for each..and[; the path detector decodes%2Eand reads zero-width and NFD forms; a linear-ratio cost test replaces the wall-clock bound; the "never activated" docs wording fixed; the URL strip stops at,,)and], so a glued path is still read; YAML anchors and tags (&pw,!secret) before inline and block values;$-prefixed values that are not a whole$VARcount as real; a JSON string layer holding JSON is checked; ssh/sftp URLs to user homes refused.Round-2 review decisions
Server=db;User Id=sa;Password=...,?user=a&password=...,a=1,password=....-is out of the key lookbehind, so--password=,--client-secret=,--api-key=are caught. Vectors plus hostile cost inputs (a=a=,-a-a-a=,"k":, 128-char keys, long values).parentlineage. Activation checks the history of every parent revision the lock lineage loads (any kit); one session-derived ancestor anywhere gates the revision, and a missing or unreadable parent fails closed. Test: an API-key private kit whose parent is a session revision of another kit gets 403, and activates from a web session.privatewhatever the first document says; only an activation sets visibility (public needs a web session). Test plus docs.content.secretKeys.qualifiers, orv2/digits):secret_key_base,api_key_prod,private_key_id,passwordValue.:=,=>andcfg["password"] =are read. Negative vectors:secretName,passwordless,passwordPolicy,tokenizerName,token_count,secretsManager,--password-file=./ ∕ ⁄ \read as separators;%25layers decode up to 3 rounds, and an encoded separator or dot left after that refuses the text.;,|,&,(,[,{,}.&a !s).Validation
pnpm test: 71 files, 1763 passed, 2 skipped.pnpm typecheck: clean.pnpm build: ok.Follow-up (AgentKit)
AgentKit has to vendor both updated JSON files, apply the new normalization order (fullwidth-only NFKC, refuse leftover escapes), the
secretKeysstems and qualifiers, theexact/subtreesallowlist shape before upload, and run the vectors in its tests. AgentKit is not changed here.🤖 Generated with Claude Code