@sema-agent/core 7.33.3 → 7.33.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/core/secret-env.js +6 -55
- package/package.json +1 -1
- package/wire-changes/core@7.33.4.json +36 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
## 7.33.4 — 2026-09-27
|
|
2
|
+
|
|
3
|
+
### Security fix — the git-family URL screen stops parsing the authority: any `@` after a `://` is a credential carrier, and on a proxy key any `@` is (#1146; 7.33.3 follow-up; behavior narrowing; +0 exports, +0 wire keys) (@server)
|
|
4
|
+
|
|
5
|
+
- **Before.** 7.33.2 and 7.33.3 read the URL authority — where it ends, which `:` belongs to a password, whether a `[` opens an IP literal — and each reading lost to an adversarial spelling: `https://[alice:secret/part@host` (a `[` that never closes; host review), `https://[a:dead%25x%oops]/part@host`, `https://[abc:def]secret/part@host`, `https://@user:secret@host`, `ssh://token%40host/r.git`, `https:/u:secret@host` (codex), `https://token/part@host` (no colon). In each the KEY cleared its exemption screen or the VALUE row did not fire, and the git group reached the host subprocess; 7.32.1 had withheld it.
|
|
6
|
+
- **Now.** One rule, no parsing: a `GIT_CONFIG_KEY_<i>` / `GIT_CONFIG_VALUE_<i>` value holding a `:/` and, anywhere after it, an `@` or its percent-encoding `%40` is a carrier (`family-rule`) — `:/` because curl reads a single slash as a URL (`https:/u:secret@host`), `%40` because git decodes it before handing the user to ssh (`ssh://token%40host/r.git`); under a proxy key (`http.proxy` / `http.<url>.proxy` / `remote.<name>.proxy`) any `@` / `%40` in the value is. Linear.
|
|
7
|
+
- **Who is hurt / compensation.** Over-drops, fail-closed (KL-1129b): a path / query / fragment `@` (`https://git.example/@scope/pkg`, `https://[::1]/repo@v2.git`, `https://h/?q=a@b`), an scp absolute path with an `@` (`host:/repo@v2.git`), an empty userinfo, a proxy value with `@` in a query, an `http.extraHeader` like `Referer: https://git.example/@scope`. The git group breaks (git exits 128) and a host's group rule withholds it. Compensation: write such a URL into the repository's config, or percent-encode the `@` (`%40`). Never over-dropped: values with no `:/` (`git@host:org/repo.git`, and `git@host:/abs` where the `@` comes first) and URLs with no `@` / `%40` after the `:/`.
|
|
8
|
+
- Pins: `test/backlog1129-git-config-key-family.test.ts` (7.33.4 block: the five review spellings on KEY and VALUE, scp / no-`@` controls, proxy `@`, 1 MiB linearity; the 7.33.1–7.33.3 authority pins re-pinned to the over-match reading).
|
|
9
|
+
|
|
1
10
|
## 7.33.3 — 2026-09-26
|
|
2
11
|
|
|
3
12
|
### Security fix — a credential written into a URL is read as a MODEL could read it: `user:secret/part@host` trips the git-family userinfo screen on KEY and VALUE (#1140; 7.33.2 follow-up; behavior; +0 exports, +0 wire keys) (@server)
|
package/dist/core/secret-env.js
CHANGED
|
@@ -16,59 +16,10 @@ const NON_SECRET_ENV_EXACT_NAMES = new Set([
|
|
|
16
16
|
"PROMPT_TOKENS", "CONTEXT_TOKENS",
|
|
17
17
|
]);
|
|
18
18
|
function carriesUrlUserinfo(value) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
let armed = false;
|
|
24
|
-
const isSchemeChar = (ch) => (ch >= 0x61 && ch <= 0x7a) || (ch >= 0x41 && ch <= 0x5a) || (ch >= 0x30 && ch <= 0x39) || ch === 0x2b || ch === 0x2e || ch === 0x2d;
|
|
25
|
-
const qualifies = (at) => open !== -1 && at > open && (sep === -1 || (colon !== -1 && colon < sep));
|
|
26
|
-
for (let i = 0; i < value.length; i++) {
|
|
27
|
-
const c = value.charCodeAt(i);
|
|
28
|
-
if (c === 0x3a && value.charCodeAt(i + 1) === 0x2f && value.charCodeAt(i + 2) === 0x2f && i > 0 && isSchemeChar(value.charCodeAt(i - 1))) {
|
|
29
|
-
if (open !== -1) {
|
|
30
|
-
if (colon === -1 && !bracket)
|
|
31
|
-
colon = i;
|
|
32
|
-
if (sep === -1)
|
|
33
|
-
sep = i + 1;
|
|
34
|
-
if (colon !== -1 && colon < sep)
|
|
35
|
-
armed = true;
|
|
36
|
-
}
|
|
37
|
-
i += 2;
|
|
38
|
-
while (value.charCodeAt(i + 1) === 0x2f)
|
|
39
|
-
i++;
|
|
40
|
-
open = i + 1;
|
|
41
|
-
colon = -1;
|
|
42
|
-
sep = -1;
|
|
43
|
-
bracket = value.charCodeAt(open) === 0x5b;
|
|
44
|
-
continue;
|
|
45
|
-
}
|
|
46
|
-
if (open === -1)
|
|
47
|
-
continue;
|
|
48
|
-
if (c === 0x40) {
|
|
49
|
-
if (armed || qualifies(i))
|
|
50
|
-
return true;
|
|
51
|
-
open = -1;
|
|
52
|
-
armed = false;
|
|
53
|
-
bracket = false;
|
|
54
|
-
continue;
|
|
55
|
-
}
|
|
56
|
-
if (bracket) {
|
|
57
|
-
if (c === 0x5d)
|
|
58
|
-
bracket = false;
|
|
59
|
-
else if (c === 0x2f || c === 0x3f || c === 0x23) {
|
|
60
|
-
bracket = false;
|
|
61
|
-
if (sep === -1)
|
|
62
|
-
sep = i;
|
|
63
|
-
}
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (colon === -1 && c === 0x3a)
|
|
67
|
-
colon = i;
|
|
68
|
-
if (sep === -1 && (c === 0x2f || c === 0x3f || c === 0x23))
|
|
69
|
-
sep = i;
|
|
70
|
-
}
|
|
71
|
-
return false;
|
|
19
|
+
const scheme = value.indexOf(":/");
|
|
20
|
+
if (scheme === -1)
|
|
21
|
+
return false;
|
|
22
|
+
return value.indexOf("@", scheme + 2) !== -1 || value.indexOf("%40", scheme + 2) !== -1;
|
|
72
23
|
}
|
|
73
24
|
const HEADER_LINE_BREAK_RE = /\r\n|\r|\n/;
|
|
74
25
|
const AUTHORIZATION_HEADER_NAME_RE = /^[ \t]*(?:(?:proxy-)?authorization|cookie)[ \t]*:/i;
|
|
@@ -88,7 +39,7 @@ function carriesAuthorizationHeader(value) {
|
|
|
88
39
|
return judge();
|
|
89
40
|
}
|
|
90
41
|
const GIT_PROXY_CONFIG_KEY_RE = /^(?:http(?:\..+)?|remote\..+)\.proxy$/is;
|
|
91
|
-
const
|
|
42
|
+
const proxyValueCarriesUserinfo = (value) => value.includes("@") || value.includes("%40");
|
|
92
43
|
const NON_SECRET_ENV_INDEXED_FAMILIES = [
|
|
93
44
|
{ stem: "GIT_CONFIG_KEY", valueClears: (value) => !carriesUrlUserinfo(value) },
|
|
94
45
|
];
|
|
@@ -99,7 +50,7 @@ const SECRET_ENV_INDEXED_FAMILIES = [
|
|
|
99
50
|
if (carriesAuthorizationHeader(value) || carriesUrlUserinfo(value))
|
|
100
51
|
return true;
|
|
101
52
|
const key = group.sibling("GIT_CONFIG_KEY");
|
|
102
|
-
return key !== undefined && GIT_PROXY_CONFIG_KEY_RE.test(key) &&
|
|
53
|
+
return key !== undefined && GIT_PROXY_CONFIG_KEY_RE.test(key) && proxyValueCarriesUserinfo(value);
|
|
103
54
|
},
|
|
104
55
|
},
|
|
105
56
|
];
|
package/package.json
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repo": "core",
|
|
3
|
+
"version": "7.33.4",
|
|
4
|
+
"from": "a7409841b2648631410f123f396f5cdac7252ae1",
|
|
5
|
+
"to": "v7.33.4",
|
|
6
|
+
"added": [],
|
|
7
|
+
"removed": [],
|
|
8
|
+
"changed": [],
|
|
9
|
+
"narrowed": [],
|
|
10
|
+
"closedSetMembers": [],
|
|
11
|
+
"closedSetsUnreadable": [],
|
|
12
|
+
"typeKeys": [],
|
|
13
|
+
"typeKeysUnreadableArms": [],
|
|
14
|
+
"typeKeysFlattenedCount": 217,
|
|
15
|
+
"declarationMoves": [],
|
|
16
|
+
"mintMoves": [],
|
|
17
|
+
"criteriaObserves": [
|
|
18
|
+
{
|
|
19
|
+
"kind": "typeMember",
|
|
20
|
+
"name": "SecretEnvFinding.kind",
|
|
21
|
+
"assertions": [
|
|
22
|
+
"G1.a",
|
|
23
|
+
"G1.b"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
],
|
|
27
|
+
"consumersHint": {
|
|
28
|
+
"cli": [],
|
|
29
|
+
"server": [],
|
|
30
|
+
"sdk": [],
|
|
31
|
+
"note": "scanned cli@4e593722 server@920701d6 sdk@10cf14c — a name listed is MENTIONED there today, which is evidence of consumption, not proof of it"
|
|
32
|
+
},
|
|
33
|
+
"breakingCount": 0,
|
|
34
|
+
"breakingItems": [],
|
|
35
|
+
"toResolvedAt": "6c61b6a5ae287d1478e469a21bf93ef2b1f56e61"
|
|
36
|
+
}
|