@amaster.ai/pi-shared 0.1.6 → 0.1.8

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.
@@ -0,0 +1,219 @@
1
+ import { lookup as nodeLookup } from 'node:dns/promises';
2
+ import { request as httpRequest } from 'node:http';
3
+ import { request as httpsRequest } from 'node:https';
4
+ import { BlockList, isIP } from 'node:net';
5
+ import { Readable } from 'node:stream';
6
+ const defaultLookup = async (hostname) => nodeLookup(hostname, { all: true, verbatim: true });
7
+ const wellKnownNat64Addresses = new BlockList();
8
+ wellKnownNat64Addresses.addSubnet('64:ff9b::', 96, 'ipv6');
9
+ const globalIpv6Addresses = new BlockList();
10
+ globalIpv6Addresses.addSubnet('2000::', 3, 'ipv6');
11
+ const nonGlobalIpv6Addresses = new BlockList();
12
+ nonGlobalIpv6Addresses.addSubnet('2001::', 23, 'ipv6');
13
+ nonGlobalIpv6Addresses.addSubnet('2001:db8::', 32, 'ipv6');
14
+ nonGlobalIpv6Addresses.addSubnet('2002::', 16, 'ipv6');
15
+ nonGlobalIpv6Addresses.addSubnet('3fff::', 20, 'ipv6');
16
+ // IANA marks 2001::/23 non-global except for these more-specific allocations.
17
+ const globalIetfProtocolAddresses = new BlockList();
18
+ globalIetfProtocolAddresses.addAddress('2001:1::1', 'ipv6');
19
+ globalIetfProtocolAddresses.addAddress('2001:1::2', 'ipv6');
20
+ globalIetfProtocolAddresses.addAddress('2001:1::3', 'ipv6');
21
+ globalIetfProtocolAddresses.addSubnet('2001:3::', 32, 'ipv6');
22
+ globalIetfProtocolAddresses.addSubnet('2001:4:112::', 48, 'ipv6');
23
+ globalIetfProtocolAddresses.addSubnet('2001:20::', 28, 'ipv6');
24
+ globalIetfProtocolAddresses.addSubnet('2001:30::', 28, 'ipv6');
25
+ function isPublicIpv4(address) {
26
+ const octets = address.split('.').map(Number);
27
+ if (octets.length !== 4 || octets.some((part) => !Number.isInteger(part)))
28
+ return false;
29
+ const [a, b, c] = octets;
30
+ if (a === 0 ||
31
+ a === 10 ||
32
+ a === 127 ||
33
+ a >= 224 ||
34
+ (a === 100 && b >= 64 && b <= 127) ||
35
+ (a === 169 && b === 254) ||
36
+ (a === 172 && b >= 16 && b <= 31) ||
37
+ (a === 192 && b === 168) ||
38
+ (a === 192 && b === 0 && c === 0) ||
39
+ (a === 192 && b === 0 && c === 2) ||
40
+ (a === 192 && b === 88 && c === 99) ||
41
+ (a === 198 && (b === 18 || b === 19 || (b === 51 && c === 100))) ||
42
+ (a === 203 && b === 0 && c === 113)) {
43
+ return false;
44
+ }
45
+ return true;
46
+ }
47
+ function mappedIpv4(address) {
48
+ const dotted = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(address);
49
+ if (dotted)
50
+ return dotted[1];
51
+ const hex = /^(?:::ffff:|(?:0{1,4}:){5}ffff:)([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(address);
52
+ if (!hex)
53
+ return undefined;
54
+ const value = Number.parseInt(hex[1], 16) * 65_536 + Number.parseInt(hex[2], 16);
55
+ return [value >>> 24, (value >>> 16) & 255, (value >>> 8) & 255, value & 255].join('.');
56
+ }
57
+ function nat64Ipv4(address) {
58
+ if (!wellKnownNat64Addresses.check(address, 'ipv6'))
59
+ return undefined;
60
+ let canonical;
61
+ try {
62
+ canonical = new URL(`http://[${address}]/`).hostname.slice(1, -1);
63
+ }
64
+ catch {
65
+ return undefined;
66
+ }
67
+ const hex = /^64:ff9b::([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(canonical);
68
+ if (!hex)
69
+ return undefined;
70
+ const value = Number.parseInt(hex[1], 16) * 65_536 + Number.parseInt(hex[2], 16);
71
+ return [value >>> 24, (value >>> 16) & 255, (value >>> 8) & 255, value & 255].join('.');
72
+ }
73
+ function isPublicIp(address) {
74
+ const normalized = address.toLowerCase().replace(/^\[|\]$/g, '');
75
+ const family = isIP(normalized);
76
+ if (family === 4)
77
+ return isPublicIpv4(normalized);
78
+ if (family !== 6)
79
+ return false;
80
+ const embeddedIpv4 = mappedIpv4(normalized) ?? nat64Ipv4(normalized);
81
+ if (embeddedIpv4)
82
+ return isPublicIpv4(embeddedIpv4);
83
+ if (!globalIpv6Addresses.check(normalized, 'ipv6'))
84
+ return false;
85
+ return (globalIetfProtocolAddresses.check(normalized, 'ipv6') ||
86
+ !nonGlobalIpv6Addresses.check(normalized, 'ipv6'));
87
+ }
88
+ /**
89
+ * Parse an outbound URL once using Node's WHATWG parser and require every DNS
90
+ * answer to be globally routable. Call this again for every redirect target.
91
+ */
92
+ async function resolvePublicHttpUrl(value, lookup = defaultLookup) {
93
+ let url;
94
+ try {
95
+ url = value instanceof URL ? new URL(value) : new URL(value);
96
+ }
97
+ catch {
98
+ throw new Error('Outbound URL must use a public HTTP(S) destination.');
99
+ }
100
+ if ((url.protocol !== 'http:' && url.protocol !== 'https:') ||
101
+ url.username ||
102
+ url.password ||
103
+ !url.hostname ||
104
+ url.hostname === 'localhost' ||
105
+ url.hostname.endsWith('.localhost')) {
106
+ throw new Error('Outbound URL must use a public HTTP(S) destination.');
107
+ }
108
+ const hostname = url.hostname.replace(/^\[|\]$/g, '');
109
+ const literalFamily = isIP(hostname);
110
+ const addresses = literalFamily
111
+ ? [{ address: hostname, family: literalFamily }]
112
+ : await lookup(hostname).catch(() => []);
113
+ if (addresses.length === 0 || addresses.some(({ address }) => !isPublicIp(address))) {
114
+ throw new Error('Outbound URL must use a public HTTP(S) destination.');
115
+ }
116
+ return { url, addresses };
117
+ }
118
+ export async function assertPublicHttpUrl(value, lookup = defaultLookup) {
119
+ return (await resolvePublicHttpUrl(value, lookup)).url;
120
+ }
121
+ export async function safeFetch(value, init = {}, options = {}) {
122
+ const lookup = options.lookup ?? defaultLookup;
123
+ const maxRedirects = options.maxRedirects ?? 5;
124
+ let resolved = await resolvePublicHttpUrl(value, lookup);
125
+ for (let redirects = 0;; redirects++) {
126
+ const response = await pinnedFetch(resolved.url, resolved.addresses[0], init);
127
+ if (![301, 302, 303, 307, 308].includes(response.status))
128
+ return response;
129
+ const location = response.headers.get('location');
130
+ if (!location || redirects >= maxRedirects) {
131
+ await response.body?.cancel().catch(() => { });
132
+ throw new Error('Outbound request exceeded the redirect limit.');
133
+ }
134
+ const next = new URL(location, resolved.url);
135
+ await response.body?.cancel().catch(() => { });
136
+ resolved = await resolvePublicHttpUrl(next, lookup);
137
+ }
138
+ }
139
+ async function pinnedFetch(url, target, init) {
140
+ const method = init.method?.toUpperCase() ?? 'GET';
141
+ if ((method === 'GET' || method === 'HEAD') && init.body) {
142
+ throw new Error(`${method} outbound requests cannot include a body.`);
143
+ }
144
+ if (init.body !== undefined &&
145
+ init.body !== null &&
146
+ typeof init.body !== 'string' &&
147
+ !(init.body instanceof Uint8Array)) {
148
+ throw new Error('Safe outbound fetch requires a replayable string or byte body.');
149
+ }
150
+ return new Promise((resolve, reject) => {
151
+ const headers = Object.fromEntries(new Headers(init.headers).entries());
152
+ const request = (url.protocol === 'https:' ? httpsRequest : httpRequest)(url, {
153
+ method,
154
+ headers,
155
+ signal: init.signal ?? undefined,
156
+ family: target.family,
157
+ lookup(_hostname, _options, callback) {
158
+ callback(null, target.address, target.family);
159
+ },
160
+ }, (incoming) => {
161
+ const responseHeaders = new Headers();
162
+ for (const [name, value] of Object.entries(incoming.headers)) {
163
+ if (Array.isArray(value)) {
164
+ for (const item of value)
165
+ responseHeaders.append(name, item);
166
+ }
167
+ else if (value !== undefined) {
168
+ responseHeaders.set(name, value);
169
+ }
170
+ }
171
+ const body = method === 'HEAD' || incoming.statusCode === 204 || incoming.statusCode === 304
172
+ ? null
173
+ : Readable.toWeb(incoming);
174
+ resolve(new Response(body, {
175
+ status: incoming.statusCode ?? 500,
176
+ statusText: incoming.statusMessage ?? '',
177
+ headers: responseHeaders,
178
+ }));
179
+ });
180
+ request.once('error', reject);
181
+ request.end(init.body ?? undefined);
182
+ });
183
+ }
184
+ export async function readResponseBytes(response, maxBytes) {
185
+ const contentLength = Number(response.headers.get('content-length'));
186
+ if (Number.isFinite(contentLength) && contentLength > maxBytes) {
187
+ await response.body?.cancel().catch(() => { });
188
+ throw new Error('Remote response exceeds the size ceiling.');
189
+ }
190
+ if (!response.body)
191
+ return new Uint8Array();
192
+ const reader = response.body.getReader();
193
+ const chunks = [];
194
+ let total = 0;
195
+ try {
196
+ for (;;) {
197
+ const { done, value } = await reader.read();
198
+ if (done)
199
+ break;
200
+ total += value.byteLength;
201
+ if (total > maxBytes) {
202
+ await reader.cancel();
203
+ throw new Error('Remote response exceeds the size ceiling.');
204
+ }
205
+ chunks.push(value);
206
+ }
207
+ }
208
+ finally {
209
+ reader.releaseLock();
210
+ }
211
+ const result = new Uint8Array(total);
212
+ let offset = 0;
213
+ for (const chunk of chunks) {
214
+ result.set(chunk, offset);
215
+ offset += chunk.byteLength;
216
+ }
217
+ return result;
218
+ }
219
+ //# sourceMappingURL=network.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,16 @@ export type PiSettingsOptions = {
2
2
  cwd?: string;
3
3
  /** Override for the config directory. If not set, resolveConfigDir() is used. */
4
4
  configDir?: string;
5
+ /** Whether project-local settings and policies may be read. Defaults to false. */
6
+ projectTrusted?: boolean;
7
+ /** Whether to expand bare $ENV_VAR references in global and agent-dir settings. Defaults to true. */
8
+ expandBareEnvVars?: boolean;
9
+ /** Refuse malformed/unreadable trusted project settings instead of ignoring them. */
10
+ strictProjectSettings?: boolean;
5
11
  };
12
+ export declare function isProjectTrusted(context: {
13
+ isProjectTrusted?: () => boolean;
14
+ } | null | undefined): boolean;
6
15
  /**
7
16
  * Resolve the user data / runtime home directory.
8
17
  * Used for: memories, data, skills, logs.
@@ -17,8 +26,10 @@ export declare function resolveConfigDir(override?: string): string;
17
26
  export declare function resolveAgentDir(override?: string): string;
18
27
  /**
19
28
  * Load extension config from pi-agent settings files.
20
- * Reads from global (~/.pi/agent/settings.json), agentDir (env/param), and project (<cwd>/.pi/settings.json).
29
+ * Reads from global (~/.pi/agent/settings.json), agentDir (env/param), and trusted project
30
+ * (<cwd>/.pi/settings.json) settings.
21
31
  * Priority from low to high: global < agentDir < project.
32
+ * Environment variables are expanded only in the global and agentDir layers.
22
33
  */
23
34
  export declare function loadPiSettings<T>(key: string, options?: PiSettingsOptions): T;
24
35
  export declare function loadJsonProfileDir<T>(dir: string): Record<string, T>;
@@ -1 +1 @@
1
- {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAsCF;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,CAAC,CAe7E;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAsBpE;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAatF"}
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,iBAAiB,GAAG;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kFAAkF;IAClF,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qGAAqG;IACrG,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,qFAAqF;IACrF,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC,CAAC;AAEF,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE;IAAE,gBAAgB,CAAC,EAAE,MAAM,OAAO,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAC/D,OAAO,CAET;AA2DD;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAO1D;AAED,mEAAmE;AACnE,wBAAgB,eAAe,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAEzD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,CAAC,CA4B7E;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAsBpE;AAED,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAgBtF"}
package/dist/settings.js CHANGED
@@ -1,9 +1,14 @@
1
1
  import { readdirSync, readFileSync } from 'node:fs';
2
2
  import { homedir } from 'node:os';
3
3
  import { basename, join, resolve } from 'node:path';
4
- function resolveEnvVars(value) {
4
+ export function isProjectTrusted(context) {
5
+ return context?.isProjectTrusted?.() === true;
6
+ }
7
+ function resolveEnvVars(value, expandBareEnvVars) {
5
8
  if (typeof value === 'string') {
6
- return value.replace(/\$\{([^}]+)\}/g, (_match, expr) => {
9
+ const pattern = expandBareEnvVars ? /\$\{([^}]+)\}|\$([A-Z_][A-Z0-9_]*)/g : /\$\{([^}]+)\}/g;
10
+ return value.replace(pattern, (_match, braced, bare) => {
11
+ const expr = braced ?? bare ?? '';
7
12
  const [name, ...rest] = expr.split(':-');
8
13
  const fallback = rest.join(':-');
9
14
  const envVal = process.env[name];
@@ -13,27 +18,40 @@ function resolveEnvVars(value) {
13
18
  });
14
19
  }
15
20
  if (Array.isArray(value)) {
16
- return value.map(resolveEnvVars);
21
+ return value.map((item) => resolveEnvVars(item, expandBareEnvVars));
17
22
  }
18
23
  if (value && typeof value === 'object') {
19
24
  const result = {};
20
25
  for (const [k, v] of Object.entries(value)) {
21
- result[k] = resolveEnvVars(v);
26
+ result[k] = resolveEnvVars(v, expandBareEnvVars);
22
27
  }
23
28
  return result;
24
29
  }
25
30
  return value;
26
31
  }
27
- function readSettingsSection(filePath, key) {
32
+ function readSettingsSection(filePath, key, options) {
28
33
  try {
29
34
  const raw = readFileSync(filePath, 'utf-8');
30
35
  const parsed = JSON.parse(raw);
31
36
  if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {
32
- return resolveEnvVars(parsed[key] ?? {});
37
+ const section = parsed[key] ?? {};
38
+ if (!section || typeof section !== 'object' || Array.isArray(section)) {
39
+ if (options.strict)
40
+ throw new Error('project settings section must be an object');
41
+ return {};
42
+ }
43
+ return (options.expandEnv ? resolveEnvVars(section, options.expandBareEnvVars) : section);
33
44
  }
45
+ if (options.strict)
46
+ throw new Error('project settings root must be an object');
34
47
  return {};
35
48
  }
36
- catch {
49
+ catch (error) {
50
+ if (error.code === 'ENOENT')
51
+ return {};
52
+ if (options.strict) {
53
+ throw new Error('Trusted project settings are unreadable or malformed.', { cause: error });
54
+ }
37
55
  return {};
38
56
  }
39
57
  }
@@ -60,18 +78,32 @@ export function resolveAgentDir(override) {
60
78
  }
61
79
  /**
62
80
  * Load extension config from pi-agent settings files.
63
- * Reads from global (~/.pi/agent/settings.json), agentDir (env/param), and project (<cwd>/.pi/settings.json).
81
+ * Reads from global (~/.pi/agent/settings.json), agentDir (env/param), and trusted project
82
+ * (<cwd>/.pi/settings.json) settings.
64
83
  * Priority from low to high: global < agentDir < project.
84
+ * Environment variables are expanded only in the global and agentDir layers.
65
85
  */
66
86
  export function loadPiSettings(key, options) {
67
87
  const globalDir = resolve(join(homedir(), '.pi', 'agent'));
68
88
  const configDir = resolveConfigDir(options?.configDir);
69
89
  const cwd = options?.cwd ?? process.cwd();
70
- const globalSettings = readSettingsSection(join(globalDir, 'settings.json'), key);
90
+ const globalSettings = readSettingsSection(join(globalDir, 'settings.json'), key, {
91
+ expandEnv: true,
92
+ expandBareEnvVars: options?.expandBareEnvVars !== false,
93
+ });
71
94
  const configSettings = configDir === globalDir
72
95
  ? {}
73
- : readSettingsSection(join(configDir, 'settings.json'), key);
74
- const projectSettings = readSettingsSection(join(cwd, '.pi', 'settings.json'), key);
96
+ : readSettingsSection(join(configDir, 'settings.json'), key, {
97
+ expandEnv: true,
98
+ expandBareEnvVars: options?.expandBareEnvVars !== false,
99
+ });
100
+ const projectSettings = options?.projectTrusted === true
101
+ ? readSettingsSection(join(cwd, '.pi', 'settings.json'), key, {
102
+ expandEnv: false,
103
+ expandBareEnvVars: false,
104
+ strict: options?.strictProjectSettings === true,
105
+ })
106
+ : {};
75
107
  return { ...globalSettings, ...configSettings, ...projectSettings };
76
108
  }
77
109
  export function loadJsonProfileDir(dir) {
@@ -108,7 +140,9 @@ export function loadPiPolicyProfiles(options) {
108
140
  const configPolicies = configPolicyDir === globalDir
109
141
  ? {}
110
142
  : loadJsonProfileDir(configPolicyDir);
111
- const projectPolicies = loadJsonProfileDir(projectDir);
143
+ const projectPolicies = options?.projectTrusted === true
144
+ ? loadJsonProfileDir(projectDir)
145
+ : {};
112
146
  return { ...globalPolicies, ...configPolicies, ...projectPolicies };
113
147
  }
114
148
  //# sourceMappingURL=settings.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../src/settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Shared threat-pattern library for memory content scanning.
3
+ *
4
+ * Covers prompt injection, role hijack, C2 framework names, exfiltration,
5
+ * persistence (SSH backdoor, agent-config edits), and invisible unicode.
6
+ *
7
+ * Pattern philosophy: anchor on attack-specific vocabulary or unambiguous
8
+ * attack behavior, NOT on bossy English. Multi-word filler is allowed via
9
+ * `(?:\w+\s+)*` between key tokens so attackers can't bypass with
10
+ * synonyms ("ignore all prior instructions").
11
+ */
12
+ type Scope = 'all' | 'context' | 'strict';
13
+ /**
14
+ * Invisible / bidirectional unicode characters used in injection attacks.
15
+ */
16
+ export declare const INVISIBLE_CHARS: ReadonlySet<string>;
17
+ /**
18
+ * Return matched pattern IDs in `content` at the given scope.
19
+ *
20
+ * - `all`: classic injection + exfil only (lowest false-positive set).
21
+ * - `context`: adds promptware / C2 / role-play patterns.
22
+ * - `strict`: adds persistence / SSH backdoor / exfil-URL patterns.
23
+ *
24
+ * Invisible-unicode hits are reported as `invisible_unicode_U+XXXX`.
25
+ */
26
+ export declare function scanForThreats(content: string, scope?: Scope): string[];
27
+ /**
28
+ * Return a human-readable error string for the first threat in `content`,
29
+ * or `null` when clean. Convenience wrapper for paths that block on first
30
+ * hit (memory writes).
31
+ */
32
+ export declare function firstThreatMessage(content: string, scope?: Scope): string | null;
33
+ export {};
34
+ //# sourceMappingURL=threat-patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"threat-patterns.d.ts","sourceRoot":"","sources":["../src/threat-patterns.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,KAAK,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,QAAQ,CAAC;AAmH1C;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,MAAM,CAkB9C,CAAC;AA0BH;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,KAAiB,GAAG,MAAM,EAAE,CA0BlF;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,KAAgB,GAAG,MAAM,GAAG,IAAI,CAW1F"}
@@ -0,0 +1,211 @@
1
+ /**
2
+ * Shared threat-pattern library for memory content scanning.
3
+ *
4
+ * Covers prompt injection, role hijack, C2 framework names, exfiltration,
5
+ * persistence (SSH backdoor, agent-config edits), and invisible unicode.
6
+ *
7
+ * Pattern philosophy: anchor on attack-specific vocabulary or unambiguous
8
+ * attack behavior, NOT on bossy English. Multi-word filler is allowed via
9
+ * `(?:\w+\s+)*` between key tokens so attackers can't bypass with
10
+ * synonyms ("ignore all prior instructions").
11
+ */
12
+ const RAW_PATTERNS = [
13
+ // Classic prompt injection (applies everywhere)
14
+ [
15
+ String.raw `ignore\s+(?:\w+\s+)*(previous|all|above|prior)\s+(?:\w+\s+)*instructions`,
16
+ 'prompt_injection',
17
+ 'all',
18
+ ],
19
+ [String.raw `system\s+prompt\s+override`, 'sys_prompt_override', 'all'],
20
+ [
21
+ String.raw `disregard\s+(?:\w+\s+)*(your|all|any)\s+(?:\w+\s+)*(instructions|rules|guidelines)`,
22
+ 'disregard_rules',
23
+ 'all',
24
+ ],
25
+ [
26
+ String.raw `act\s+as\s+(if|though)\s+(?:\w+\s+)*you\s+(?:\w+\s+)*(have\s+no|don't\s+have)\s+(?:\w+\s+)*(restrictions|limits|rules)`,
27
+ 'bypass_restrictions',
28
+ 'all',
29
+ ],
30
+ ['<!--[^>]*(?:ignore|override|system|secret|hidden)[^>]*-->', 'html_comment_injection', 'all'],
31
+ [String.raw `<\s*div\s+style\s*=\s*["'][\s\S]*?display\s*:\s*none`, 'hidden_div', 'all'],
32
+ [String.raw `translate\s+.*\s+into\s+.*\s+and\s+(execute|run|eval)`, 'translate_execute', 'all'],
33
+ [String.raw `do\s+not\s+(?:\w+\s+)*tell\s+(?:\w+\s+)*the\s+user`, 'deception_hide', 'all'],
34
+ // Role-play / identity hijack (context + strict)
35
+ [String.raw `you\s+are\s+(?:\w+\s+)*now\s+(?:a|an|the)\s+`, 'role_hijack', 'context'],
36
+ [String.raw `pretend\s+(?:\w+\s+)*(you\s+are|to\s+be)\s+`, 'role_pretend', 'context'],
37
+ [String.raw `output\s+(?:\w+\s+)*(system|initial)\s+prompt`, 'leak_system_prompt', 'context'],
38
+ [
39
+ String.raw `(respond|answer|reply)\s+without\s+(?:\w+\s+)*(restrictions|limitations|filters|safety)`,
40
+ 'remove_filters',
41
+ 'context',
42
+ ],
43
+ [
44
+ String.raw `you\s+have\s+been\s+(?:\w+\s+)*(updated|upgraded|patched)\s+to`,
45
+ 'fake_update',
46
+ 'context',
47
+ ],
48
+ [String.raw `\bname\s+yourself\s+\w+`, 'identity_override', 'context'],
49
+ // C2 / Brainworm-style promptware
50
+ [String.raw `register\s+(as\s+)?a?\s*node`, 'c2_node_registration', 'context'],
51
+ [String.raw `(heartbeat|beacon|check[\s\-]?in)\s+(to|with)\s+`, 'c2_heartbeat', 'context'],
52
+ [String.raw `pull\s+(down\s+)?(?:new\s+)?task(?:ing|s)?\b`, 'c2_task_pull', 'context'],
53
+ [String.raw `connect\s+to\s+the\s+network\b`, 'c2_network_connect', 'context'],
54
+ [
55
+ String.raw `you\s+must\s+(?:\w+\s+){0,3}(register|connect|report|beacon)\b`,
56
+ 'forced_action',
57
+ 'context',
58
+ ],
59
+ [String.raw `only\s+use\s+one[\s\-]?liners?\b`, 'anti_forensic_oneliner', 'context'],
60
+ [
61
+ String.raw `never\s+(?:\w+\s+)*(?:create|write)\s+(?:\w+\s+)*(?:script|file)\s+(?:\w+\s+)*disk`,
62
+ 'anti_forensic_disk',
63
+ 'context',
64
+ ],
65
+ [
66
+ String.raw `unset\s+\w*(?:CLAUDE|CODEX|HERMES|AGENT|OPENAI|ANTHROPIC|PI)\w*`,
67
+ 'env_var_unset_agent',
68
+ 'context',
69
+ ],
70
+ // Known C2 framework names
71
+ [
72
+ String.raw `\b(?:praxis|cobalt\s*strike|sliver|havoc|mythic|metasploit|brainworm)\b`,
73
+ 'known_c2_framework',
74
+ 'context',
75
+ ],
76
+ [String.raw `\bc2\s+(?:server|channel|infrastructure|beacon)\b`, 'c2_explicit', 'context'],
77
+ [String.raw `\bcommand\s+and\s+control\b`, 'c2_explicit_long', 'context'],
78
+ // Exfiltration via curl/wget/cat with secrets
79
+ [
80
+ String.raw `curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)`,
81
+ 'exfil_curl',
82
+ 'all',
83
+ ],
84
+ [
85
+ String.raw `wget\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL|API)`,
86
+ 'exfil_wget',
87
+ 'all',
88
+ ],
89
+ [
90
+ String.raw `cat\s+[^\n]*(\.env|credentials|\.netrc|\.pgpass|\.npmrc|\.pypirc)`,
91
+ 'read_secrets',
92
+ 'all',
93
+ ],
94
+ [String.raw `(send|post|upload|transmit)\s+.*\s+(to|at)\s+https?://`, 'send_to_url', 'strict'],
95
+ [
96
+ String.raw `(include|output|print|share)\s+(?:\w+\s+)*(conversation|chat\s+history|previous\s+messages|full\s+context|entire\s+context)`,
97
+ 'context_exfil',
98
+ 'strict',
99
+ ],
100
+ // Persistence / SSH backdoor (strict scope)
101
+ ['authorized_keys', 'ssh_backdoor', 'strict'],
102
+ [String.raw `\$HOME/\.ssh|~/\.ssh`, 'ssh_access', 'strict'],
103
+ [String.raw `\$HOME/\.pi/\.env|~/\.pi/\.env`, 'pi_env', 'strict'],
104
+ [
105
+ String.raw `(update|modify|edit|write|change|append|add\s+to)\s+.*(?:AGENTS\.md|CLAUDE\.md|\.cursorrules|\.clinerules)`,
106
+ 'agent_config_mod',
107
+ 'strict',
108
+ ],
109
+ // Hardcoded secrets
110
+ [
111
+ String.raw `(?:api[_-]?key|token|secret|password)\s*[=:]\s*["'][A-Za-z0-9+/=_-]{20,}`,
112
+ 'hardcoded_secret',
113
+ 'strict',
114
+ ],
115
+ ];
116
+ /**
117
+ * Invisible / bidirectional unicode characters used in injection attacks.
118
+ */
119
+ export const INVISIBLE_CHARS = new Set([
120
+ '​', // zero-width space
121
+ '‌', // zero-width non-joiner
122
+ '‍', // zero-width joiner
123
+ '⁠', // word joiner
124
+ '⁢', // invisible times
125
+ '⁣', // invisible separator
126
+ '⁤', // invisible plus
127
+ '', // zero-width no-break space (BOM)
128
+ '‪', // left-to-right embedding
129
+ '‫', // right-to-left embedding
130
+ '‬', // pop directional formatting
131
+ '‭', // left-to-right override
132
+ '‮', // right-to-left override
133
+ '⁦', // left-to-right isolate
134
+ '⁧', // right-to-left isolate
135
+ '⁨', // first strong isolate
136
+ '⁩', // pop directional isolate
137
+ ]);
138
+ function buildScopeSets() {
139
+ const all = [];
140
+ const context = [];
141
+ const strict = [];
142
+ for (const [pattern, id, scope] of RAW_PATTERNS) {
143
+ const compiled = [new RegExp(pattern, 'i'), id];
144
+ if (scope === 'all') {
145
+ all.push(compiled);
146
+ context.push(compiled);
147
+ strict.push(compiled);
148
+ }
149
+ else if (scope === 'context') {
150
+ context.push(compiled);
151
+ strict.push(compiled);
152
+ }
153
+ else {
154
+ strict.push(compiled);
155
+ }
156
+ }
157
+ return { all, context, strict };
158
+ }
159
+ const COMPILED = buildScopeSets();
160
+ /**
161
+ * Return matched pattern IDs in `content` at the given scope.
162
+ *
163
+ * - `all`: classic injection + exfil only (lowest false-positive set).
164
+ * - `context`: adds promptware / C2 / role-play patterns.
165
+ * - `strict`: adds persistence / SSH backdoor / exfil-URL patterns.
166
+ *
167
+ * Invisible-unicode hits are reported as `invisible_unicode_U+XXXX`.
168
+ */
169
+ export function scanForThreats(content, scope = 'context') {
170
+ if (!content) {
171
+ return [];
172
+ }
173
+ const findings = [];
174
+ for (const ch of content) {
175
+ if (INVISIBLE_CHARS.has(ch)) {
176
+ const code = ch.codePointAt(0).toString(16).toUpperCase().padStart(4, '0');
177
+ const finding = `invisible_unicode_U+${code}`;
178
+ if (!findings.includes(finding)) {
179
+ findings.push(finding);
180
+ }
181
+ }
182
+ }
183
+ const patterns = COMPILED[scope];
184
+ if (!patterns) {
185
+ throw new Error(`scanForThreats: unknown scope '${scope}'`);
186
+ }
187
+ for (const [regex, id] of patterns) {
188
+ if (regex.test(content)) {
189
+ findings.push(id);
190
+ }
191
+ }
192
+ return findings;
193
+ }
194
+ /**
195
+ * Return a human-readable error string for the first threat in `content`,
196
+ * or `null` when clean. Convenience wrapper for paths that block on first
197
+ * hit (memory writes).
198
+ */
199
+ export function firstThreatMessage(content, scope = 'strict') {
200
+ const findings = scanForThreats(content, scope);
201
+ if (findings.length === 0) {
202
+ return null;
203
+ }
204
+ const id = findings[0];
205
+ if (id.startsWith('invisible_unicode_')) {
206
+ const codepoint = id.replace('invisible_unicode_', '');
207
+ return `Blocked: content contains invisible unicode character ${codepoint} (possible injection).`;
208
+ }
209
+ return `Blocked: content matches threat pattern '${id}'. Content is injected into the system prompt and must not contain injection or exfiltration payloads.`;
210
+ }
211
+ //# sourceMappingURL=threat-patterns.js.map