For AI agents: every page on this site is listed at /llms.txt, and this page is also available as Markdown.

Credential leak contract

Owner-ruled 2026-10-29. This is the fixed target for every credential check and every review of a connector under skills/*/cli and of the shared credential kit (tools/maintainer/credkit). A review judges credential findings against this document. A finding outside it is P2 at most, unless it shows a held credential leaving through a sink this document covers in a reading section 3 names. Changing a rule here needs the owner; a review cannot.

Amended 2026-10-29, owner-approved: section 3 is a closed list, the budget is an invariant with no clean exit, public text is defined and used only for collisions (it exempts no piece), and the kit’s matcher is the one implementation (section 8).

Amended 2026-10-30, owner-approved: section 3 names eight reading bounds, and a reading the bounds leave out is out of scope, P2 at most, the same as an encoding the closed list does not name.

Amended 2026-10-31, owner-approved: a ninth reading bound says which spans of a run decoder are decoded further. A credential reachable only through an end of a span that bound leaves out is out of scope, P2 at most. Section 6 gains item 8, the destination host inside an https tunnel through a proxy.

Amended 2026-11-01, owner-approved: section 6 gains item 9, a single write to stdout or stderr that the platform splits at a pause.

Amended 2026-11-02, owner-approved: section 6 gains item 10, a JSON document that a modal charset reading holds only after a further decoding.

Amended 2026-11-02, owner order: a tenth reading bound says ROT13 reads a text view the kit reads whole, not the runs it cuts from a charset reading or a decoder’s text output. A credential reachable only through ROT13 of such a run is out of scope, P2 at most.

1. Held credentials

A held credential is every value the program uses or receives as a secret:

Rules for the held set:

Public text is fixed text a connector emits whether or not it holds any credential. It is used only for the collision rules of section 2 and exempts no piece. It is exactly the entries of one public-text table in the kit’s source. Nothing outside that table is public text, and a table entry that is not one of these kinds breaks this clause:

  1. The fixed text of the kit’s own notices: the withhold notices, the startup refusal, the record of an unheld value, and the replacement the kit writes for a withheld header. The names a notice fills in at run time, such as a variable or field name, are not public text.
  2. HTTP protocol text: the version tokens HTTP/1.0 and HTTP/1.1, each reason phrase that Go’s net/http.StatusText returns at the Go version in the kit’s go.mod, each status line built from a version, a code and its reason phrase, and the header field names in the IANA HTTP Field Name Registry.
  3. The JSON-RPC 2.0 envelope: the member names jsonrpc, id, method, params, result, error, code, message and data, the member "jsonrpc":"2.0", and the reserved error codes with the messages the JSON-RPC 2.0 specification gives them.
  4. The server-sent events field names event, data, id and retry.
  5. The JSON literals true, false and null.
  6. Text the operating system or the Go runtime adds on its own, which is exactly this: the variable name SYSTEMROOT, which Go’s os/exec adds to a child process environment on Windows. Its value is machine-specific and is not public text.

2. What counts as a leak

An emitted unit leaks when, after the decoding in section 3, it contains any of these:

An outbound request is judged by (c) alone. A credential sent over https to one of its own allowed origins, and not carried across a redirect to a different origin, is the program working, not a leak. Every other unit is judged by (a) and (b).

An origin is the scheme, host and port, with the scheme’s default port when none is written. The host is compared after lowercasing and IDNA conversion. An allowed origin written as https://*.example.com matches any subdomain of example.com on port 443, and not example.com itself.

A character is a Unicode code point, or a byte for a value that is not valid UTF-8.

Public text. Public text is a fixed, published table, so a value that collides with it could be guessed from the table alone, and holding it would withhold the protocol text that ordinary units carry. It is used only for these collision rules and exempts nothing at any sink, outbound requests included:

An emitted unit is one of:

3. Decoders

This list is complete. An encoding, format, charset or spelling that this section does not name is out of scope: a unit that carries a held credential only through one is not a leak, and a review may raise it as P2 at most. A review finding about decoding must name the clause of this section that the matcher breaks. The matcher may read more than this section names; a match there withholds the unit, but the absence of an unnamed reading is never a finding.

Views. A view is the raw bytes of a unit, or what one decoder below produces from a view. Every view, whatever its length or content (text, binary, mixed, one character), is compared under section 2 and read by every decoder (Recursion), within the reading bounds below. A candidate that a decoder’s rule does not accept gives no view.

Candidates. Each decoder below is of one of three kinds, and its kind fixes where its candidates start and end:

The decoders:

Also:

4. What happens on a match

5. Sinks covered

6. Advisory cases (tracked, never blocking)

A review may raise these as P2, never as P1:

  1. The MCP client’s own JSON-RPC request id echoed back to it.
  2. Scientific-notation spellings of a number, unless the held credential is made only of digits.
  3. Numeric vendor fields the connector does not declare as credentials.
  4. Values the ledger declares identifiers, with a reason.
  5. A credential split across two separate runs of the program.
  6. Pieces shorter than 8 characters, other than the whole-token rule in 2(a).
  7. Ordinary output that exhausts the budget (section 3, budget quality target).
  8. The destination host, in its Punycode (IDNA) spelling, inside the https request a CONNECT tunnel carries through a proxy. The CONNECT line the proxy receives, which names that host too, is judged under section 2(c) like any outbound request.
  9. A single write to stdout or stderr that the platform splits at a pause (the pipe stays empty for the pause length while the kit waits): the two parts are checked as two writes of the stream, so no held credential passes whole and fewer than 8 of its characters reach the sink before the part that completes it.
  10. A JSON document that a modal charset reading (ISO-2022-JP or HZ) holds only after a further decoding of that reading, such as percent-encoding, when the reading also holds a character that is in no held value. The kit joins a modal reading whole as it reads it, but a reading that must be decoded again is decoded in its runs of relevant characters, so that character splits the document before the join reads it. Example: the hex of an ISO-2022-JP text that reads %7B"あ":0,"a":"secr","b":"et!!"} needs hex, ISO-2022-JP, percent-encoding and the join, four decodings in a row.

7. Per-connector declarations

Each connector records these in its hand-fix ledger:

Declarations in Go source are read from the files the connector’s build compiles, under the build tags and flags that build uses. A declaration the reader cannot interpret is a failure, never an empty declaration.

8. One implementation

The kit’s matcher is the only implementation of sections 2 and 3. The leak test list does not carry its own copy: it calls the kit’s matcher through a small command (the held set and a unit in, one verdict out: clean, match or exhausted) and judges every case by that verdict. A matcher fix therefore lands once and reaches both. A difference between what the kit withholds and what the list reports is a defect in the command or the list, never a second reading of this contract. How the list chooses, names and baselines its cases, and the integrity of its own code, are outside this contract.