@integsec/agentic-pentest-proxy 0.1.0
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/README.md +731 -0
- package/dist/bin/integsec-agentic-pentest-proxy.d.ts +3 -0
- package/dist/bin/integsec-agentic-pentest-proxy.d.ts.map +1 -0
- package/dist/bin/integsec-agentic-pentest-proxy.js +51 -0
- package/dist/bin/integsec-agentic-pentest-proxy.js.map +1 -0
- package/dist/src/audit/azure-monitor.d.ts +22 -0
- package/dist/src/audit/azure-monitor.d.ts.map +1 -0
- package/dist/src/audit/azure-monitor.js +62 -0
- package/dist/src/audit/azure-monitor.js.map +1 -0
- package/dist/src/audit/cloudwatch.d.ts +20 -0
- package/dist/src/audit/cloudwatch.d.ts.map +1 -0
- package/dist/src/audit/cloudwatch.js +89 -0
- package/dist/src/audit/cloudwatch.js.map +1 -0
- package/dist/src/audit/gcp-logging.d.ts +23 -0
- package/dist/src/audit/gcp-logging.d.ts.map +1 -0
- package/dist/src/audit/gcp-logging.js +70 -0
- package/dist/src/audit/gcp-logging.js.map +1 -0
- package/dist/src/audit/index.d.ts +49 -0
- package/dist/src/audit/index.d.ts.map +1 -0
- package/dist/src/audit/index.js +79 -0
- package/dist/src/audit/index.js.map +1 -0
- package/dist/src/audit/local.d.ts +25 -0
- package/dist/src/audit/local.d.ts.map +1 -0
- package/dist/src/audit/local.js +51 -0
- package/dist/src/audit/local.js.map +1 -0
- package/dist/src/config.d.ts +25 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +26 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/dns-resolver.d.ts +21 -0
- package/dist/src/dns-resolver.d.ts.map +1 -0
- package/dist/src/dns-resolver.js +68 -0
- package/dist/src/dns-resolver.js.map +1 -0
- package/dist/src/domain-matcher.d.ts +35 -0
- package/dist/src/domain-matcher.d.ts.map +1 -0
- package/dist/src/domain-matcher.js +97 -0
- package/dist/src/domain-matcher.js.map +1 -0
- package/dist/src/extractor.d.ts +30 -0
- package/dist/src/extractor.d.ts.map +1 -0
- package/dist/src/extractor.js +176 -0
- package/dist/src/extractor.js.map +1 -0
- package/dist/src/index.d.ts +8 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +7 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/ip-matcher.d.ts +38 -0
- package/dist/src/ip-matcher.d.ts.map +1 -0
- package/dist/src/ip-matcher.js +128 -0
- package/dist/src/ip-matcher.js.map +1 -0
- package/dist/src/manifest-schema.d.ts +77 -0
- package/dist/src/manifest-schema.d.ts.map +1 -0
- package/dist/src/manifest-schema.js +34 -0
- package/dist/src/manifest-schema.js.map +1 -0
- package/dist/src/manifest.d.ts +3 -0
- package/dist/src/manifest.d.ts.map +1 -0
- package/dist/src/manifest.js +115 -0
- package/dist/src/manifest.js.map +1 -0
- package/dist/src/proxy.d.ts +16 -0
- package/dist/src/proxy.d.ts.map +1 -0
- package/dist/src/proxy.js +72 -0
- package/dist/src/proxy.js.map +1 -0
- package/dist/src/sanitizer.d.ts +19 -0
- package/dist/src/sanitizer.d.ts.map +1 -0
- package/dist/src/sanitizer.js +68 -0
- package/dist/src/sanitizer.js.map +1 -0
- package/dist/src/technique-checker.d.ts +50 -0
- package/dist/src/technique-checker.d.ts.map +1 -0
- package/dist/src/technique-checker.js +110 -0
- package/dist/src/technique-checker.js.map +1 -0
- package/dist/src/transports/http.d.ts +3 -0
- package/dist/src/transports/http.d.ts.map +1 -0
- package/dist/src/transports/http.js +67 -0
- package/dist/src/transports/http.js.map +1 -0
- package/dist/src/transports/stdio.d.ts +3 -0
- package/dist/src/transports/stdio.d.ts.map +1 -0
- package/dist/src/transports/stdio.js +50 -0
- package/dist/src/transports/stdio.js.map +1 -0
- package/dist/src/types.d.ts +43 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/validator.d.ts +54 -0
- package/dist/src/validator.d.ts.map +1 -0
- package/dist/src/validator.js +200 -0
- package/dist/src/validator.js.map +1 -0
- package/examples/claude-desktop-config.json +15 -0
- package/examples/scope-manifest.json +18 -0
- package/examples/technique-map.json +10 -0
- package/package.json +58 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function loadConfig() {
|
|
2
|
+
return {
|
|
3
|
+
manifestPath: process.env.SCOPE_MANIFEST_PATH,
|
|
4
|
+
manifestJson: process.env.SCOPE_MANIFEST_JSON,
|
|
5
|
+
manifestSecretArn: process.env.SCOPE_MANIFEST_SECRET_ARN,
|
|
6
|
+
manifestKeyvaultUri: process.env.SCOPE_MANIFEST_KEYVAULT_URI,
|
|
7
|
+
manifestGcpSecret: process.env.SCOPE_MANIFEST_GCP_SECRET,
|
|
8
|
+
transport: process.env.MCP_TRANSPORT || "stdio",
|
|
9
|
+
upstreamMcpUrl: process.env.UPSTREAM_MCP_URL,
|
|
10
|
+
upstreamMcpCommand: process.env.UPSTREAM_MCP_COMMAND,
|
|
11
|
+
upstreamMcpArgs: process.env.UPSTREAM_MCP_ARGS?.split(","),
|
|
12
|
+
proxyPort: parseInt(process.env.PROXY_PORT || "9090", 10),
|
|
13
|
+
auditLogPath: process.env.AUDIT_LOG_PATH || "./audit/",
|
|
14
|
+
awsLogGroup: process.env.AWS_LOG_GROUP,
|
|
15
|
+
awsRegion: process.env.AWS_REGION,
|
|
16
|
+
azureLogWorkspaceId: process.env.AZURE_LOG_WORKSPACE_ID,
|
|
17
|
+
azureDcrImmutableId: process.env.AZURE_DCR_IMMUTABLE_ID,
|
|
18
|
+
azureDcrStreamName: process.env.AZURE_DCR_STREAM_NAME || "Custom-MCPProxyAudit_CL",
|
|
19
|
+
gcpProject: process.env.GOOGLE_CLOUD_PROJECT,
|
|
20
|
+
techniqueMapPath: process.env.TECHNIQUE_MAP_PATH,
|
|
21
|
+
dnsCacheTtl: parseInt(process.env.DNS_CACHE_TTL || "60", 10),
|
|
22
|
+
logLevel: process.env.LOG_LEVEL || "INFO",
|
|
23
|
+
proxyVersion: process.env.PROXY_VERSION || "0.1.0",
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/config.ts"],"names":[],"mappings":"AAwBA,MAAM,UAAU,UAAU;IACxB,OAAO;QACL,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC7C,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC7C,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;QACxD,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,2BAA2B;QAC5D,iBAAiB,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB;QACxD,SAAS,EAAG,OAAO,CAAC,GAAG,CAAC,aAAiC,IAAI,OAAO;QACpE,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,gBAAgB;QAC5C,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QACpD,eAAe,EAAE,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,KAAK,CAAC,GAAG,CAAC;QAC1D,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,IAAI,MAAM,EAAE,EAAE,CAAC;QACzD,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,UAAU;QACtD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa;QACtC,SAAS,EAAE,OAAO,CAAC,GAAG,CAAC,UAAU;QACjC,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;QACvD,mBAAmB,EAAE,OAAO,CAAC,GAAG,CAAC,sBAAsB;QACvD,kBAAkB,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,yBAAyB;QAClF,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB;QAC5C,gBAAgB,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAChD,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,IAAI,EAAE,EAAE,CAAC;QAC5D,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,MAAM;QACzC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO;KACnD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS resolver with TTL-based caching.
|
|
3
|
+
*
|
|
4
|
+
* - Raw IP addresses are returned immediately without any DNS lookup.
|
|
5
|
+
* - Both A (IPv4) and AAAA (IPv6) records are resolved in parallel.
|
|
6
|
+
* - Results are cached for `ttlSeconds`; a TTL of 0 disables caching.
|
|
7
|
+
* - If both record types fail the method returns an empty array (never throws).
|
|
8
|
+
* - In-flight requests for the same hostname are de-duplicated so that
|
|
9
|
+
* concurrent callers share a single DNS round-trip.
|
|
10
|
+
*/
|
|
11
|
+
export declare class DnsResolver {
|
|
12
|
+
private readonly ttlMs;
|
|
13
|
+
private readonly cache;
|
|
14
|
+
/** Promises for in-flight lookups, keyed by hostname. */
|
|
15
|
+
private readonly inflight;
|
|
16
|
+
constructor(ttlSeconds?: number);
|
|
17
|
+
resolve(target: string): Promise<string[]>;
|
|
18
|
+
/** Perform the actual A + AAAA DNS queries in parallel. Never throws. */
|
|
19
|
+
private _lookup;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=dns-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-resolver.d.ts","sourceRoot":"","sources":["../../src/dns-resolver.ts"],"names":[],"mappings":"AAQA;;;;;;;;;GASG;AACH,qBAAa,WAAW;IACtB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,yDAAyD;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;gBAErD,UAAU,GAAE,MAAW;IAI7B,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAoChD,yEAAyE;YAC3D,OAAO;CAkBtB"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { isIP } from "net";
|
|
2
|
+
import dns from "dns/promises";
|
|
3
|
+
/**
|
|
4
|
+
* DNS resolver with TTL-based caching.
|
|
5
|
+
*
|
|
6
|
+
* - Raw IP addresses are returned immediately without any DNS lookup.
|
|
7
|
+
* - Both A (IPv4) and AAAA (IPv6) records are resolved in parallel.
|
|
8
|
+
* - Results are cached for `ttlSeconds`; a TTL of 0 disables caching.
|
|
9
|
+
* - If both record types fail the method returns an empty array (never throws).
|
|
10
|
+
* - In-flight requests for the same hostname are de-duplicated so that
|
|
11
|
+
* concurrent callers share a single DNS round-trip.
|
|
12
|
+
*/
|
|
13
|
+
export class DnsResolver {
|
|
14
|
+
ttlMs;
|
|
15
|
+
cache = new Map();
|
|
16
|
+
/** Promises for in-flight lookups, keyed by hostname. */
|
|
17
|
+
inflight = new Map();
|
|
18
|
+
constructor(ttlSeconds = 60) {
|
|
19
|
+
this.ttlMs = ttlSeconds * 1000;
|
|
20
|
+
}
|
|
21
|
+
async resolve(target) {
|
|
22
|
+
// 1. Raw IP — return immediately, no lookup, no caching needed.
|
|
23
|
+
if (isIP(target) !== 0) {
|
|
24
|
+
return [target];
|
|
25
|
+
}
|
|
26
|
+
// 2. Cache hit — return if still within TTL.
|
|
27
|
+
const cached = this.cache.get(target);
|
|
28
|
+
if (cached !== undefined && Date.now() < cached.expiresAt) {
|
|
29
|
+
return cached.addresses;
|
|
30
|
+
}
|
|
31
|
+
// 3. In-flight de-duplication — if there is already a pending lookup for
|
|
32
|
+
// this hostname, piggyback on it rather than issuing a second request.
|
|
33
|
+
const existing = this.inflight.get(target);
|
|
34
|
+
if (existing !== undefined) {
|
|
35
|
+
return existing;
|
|
36
|
+
}
|
|
37
|
+
// 4. Issue a fresh lookup and register it as in-flight.
|
|
38
|
+
const lookupPromise = this._lookup(target).then((addresses) => {
|
|
39
|
+
// Store in cache (even an empty result, to avoid hammering failed names).
|
|
40
|
+
if (this.ttlMs > 0) {
|
|
41
|
+
this.cache.set(target, {
|
|
42
|
+
addresses,
|
|
43
|
+
expiresAt: Date.now() + this.ttlMs,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
this.inflight.delete(target);
|
|
47
|
+
return addresses;
|
|
48
|
+
});
|
|
49
|
+
this.inflight.set(target, lookupPromise);
|
|
50
|
+
return lookupPromise;
|
|
51
|
+
}
|
|
52
|
+
/** Perform the actual A + AAAA DNS queries in parallel. Never throws. */
|
|
53
|
+
async _lookup(hostname) {
|
|
54
|
+
const [v4Result, v6Result] = await Promise.allSettled([
|
|
55
|
+
dns.resolve4(hostname),
|
|
56
|
+
dns.resolve6(hostname),
|
|
57
|
+
]);
|
|
58
|
+
const addresses = [];
|
|
59
|
+
if (v4Result.status === "fulfilled") {
|
|
60
|
+
addresses.push(...v4Result.value);
|
|
61
|
+
}
|
|
62
|
+
if (v6Result.status === "fulfilled") {
|
|
63
|
+
addresses.push(...v6Result.value);
|
|
64
|
+
}
|
|
65
|
+
return addresses;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=dns-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dns-resolver.js","sourceRoot":"","sources":["../../src/dns-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAC3B,OAAO,GAAG,MAAM,cAAc,CAAC;AAO/B;;;;;;;;;GASG;AACH,MAAM,OAAO,WAAW;IACL,KAAK,CAAS;IACd,KAAK,GAAG,IAAI,GAAG,EAAsB,CAAC;IACvD,yDAAyD;IACxC,QAAQ,GAAG,IAAI,GAAG,EAA6B,CAAC;IAEjE,YAAY,aAAqB,EAAE;QACjC,IAAI,CAAC,KAAK,GAAG,UAAU,GAAG,IAAI,CAAC;IACjC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAc;QAC1B,gEAAgE;QAChE,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACvB,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC;QAED,6CAA6C;QAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;YAC1D,OAAO,MAAM,CAAC,SAAS,CAAC;QAC1B,CAAC;QAED,yEAAyE;QACzE,0EAA0E;QAC1E,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAC3C,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YAC3B,OAAO,QAAQ,CAAC;QAClB,CAAC;QAED,wDAAwD;QACxD,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YAC5D,0EAA0E;YAC1E,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;gBACnB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE;oBACrB,SAAS;oBACT,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK;iBACnC,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC7B,OAAO,SAAS,CAAC;QACnB,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACzC,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,yEAAyE;IACjE,KAAK,CAAC,OAAO,CAAC,QAAgB;QACpC,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;YACpD,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;YACtB,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC;SACvB,CAAC,CAAC;QAEH,MAAM,SAAS,GAAa,EAAE,CAAC;QAE/B,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACpC,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,IAAI,QAAQ,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YACpC,SAAS,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;QACpC,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* domain-matcher.ts
|
|
3
|
+
*
|
|
4
|
+
* Utilities for matching hostnames against domain patterns used in scope
|
|
5
|
+
* enforcement. This is a SECURITY-CRITICAL module — an incorrect match means
|
|
6
|
+
* attacking the wrong target.
|
|
7
|
+
*
|
|
8
|
+
* Supported pattern forms:
|
|
9
|
+
* - Exact: "acme-staging.example.com"
|
|
10
|
+
* - Wildcard: "*.acme.com" (matches exactly ONE subdomain level, not the
|
|
11
|
+
* apex and not deeper nesting)
|
|
12
|
+
*
|
|
13
|
+
* All comparisons are case-insensitive. Trailing DNS dots are stripped from
|
|
14
|
+
* both inputs before any comparison.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Match a hostname against a single pattern.
|
|
18
|
+
*
|
|
19
|
+
* Rules:
|
|
20
|
+
* - Both inputs are normalized (lower-cased, trailing dot stripped).
|
|
21
|
+
* - Empty strings never match.
|
|
22
|
+
* - Wildcard prefix `*.` is the ONLY supported wildcard form.
|
|
23
|
+
* `*.acme.com` matches `foo.acme.com` but NOT `acme.com` and NOT
|
|
24
|
+
* `foo.bar.acme.com`.
|
|
25
|
+
* - Any pattern that does not start with `*.` is treated as an exact match.
|
|
26
|
+
* - Unicode labels (non-ASCII) are compared byte-for-byte after lower-casing;
|
|
27
|
+
* they will only match an identical unicode pattern, not an ASCII wildcard.
|
|
28
|
+
*/
|
|
29
|
+
export declare function matchesDomain(hostname: string, pattern: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Return true if the hostname matches at least one pattern in the array.
|
|
32
|
+
* Returns false immediately for an empty patterns array.
|
|
33
|
+
*/
|
|
34
|
+
export declare function matchesAnyDomain(hostname: string, patterns: string[]): boolean;
|
|
35
|
+
//# sourceMappingURL=domain-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-matcher.d.ts","sourceRoot":"","sources":["../../src/domain-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAeH;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA2DxE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,OAAO,CAE9E"}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* domain-matcher.ts
|
|
3
|
+
*
|
|
4
|
+
* Utilities for matching hostnames against domain patterns used in scope
|
|
5
|
+
* enforcement. This is a SECURITY-CRITICAL module — an incorrect match means
|
|
6
|
+
* attacking the wrong target.
|
|
7
|
+
*
|
|
8
|
+
* Supported pattern forms:
|
|
9
|
+
* - Exact: "acme-staging.example.com"
|
|
10
|
+
* - Wildcard: "*.acme.com" (matches exactly ONE subdomain level, not the
|
|
11
|
+
* apex and not deeper nesting)
|
|
12
|
+
*
|
|
13
|
+
* All comparisons are case-insensitive. Trailing DNS dots are stripped from
|
|
14
|
+
* both inputs before any comparison.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Normalize a hostname or pattern by:
|
|
18
|
+
* 1. Lower-casing it (DNS is case-insensitive).
|
|
19
|
+
* 2. Stripping a single trailing dot (absolute FQDN notation).
|
|
20
|
+
*/
|
|
21
|
+
function normalize(value) {
|
|
22
|
+
let s = value.toLowerCase();
|
|
23
|
+
if (s.endsWith(".")) {
|
|
24
|
+
s = s.slice(0, -1);
|
|
25
|
+
}
|
|
26
|
+
return s;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Match a hostname against a single pattern.
|
|
30
|
+
*
|
|
31
|
+
* Rules:
|
|
32
|
+
* - Both inputs are normalized (lower-cased, trailing dot stripped).
|
|
33
|
+
* - Empty strings never match.
|
|
34
|
+
* - Wildcard prefix `*.` is the ONLY supported wildcard form.
|
|
35
|
+
* `*.acme.com` matches `foo.acme.com` but NOT `acme.com` and NOT
|
|
36
|
+
* `foo.bar.acme.com`.
|
|
37
|
+
* - Any pattern that does not start with `*.` is treated as an exact match.
|
|
38
|
+
* - Unicode labels (non-ASCII) are compared byte-for-byte after lower-casing;
|
|
39
|
+
* they will only match an identical unicode pattern, not an ASCII wildcard.
|
|
40
|
+
*/
|
|
41
|
+
export function matchesDomain(hostname, pattern) {
|
|
42
|
+
// Reject empty inputs immediately — they are meaningless in scope checking.
|
|
43
|
+
if (!hostname || !pattern) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const normalizedHost = normalize(hostname);
|
|
47
|
+
const normalizedPattern = normalize(pattern);
|
|
48
|
+
// A second empty-check after normalization (e.g. input was just ".")
|
|
49
|
+
if (!normalizedHost || !normalizedPattern) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
// Wildcard pattern: must start with "*."
|
|
53
|
+
if (normalizedPattern.startsWith("*.")) {
|
|
54
|
+
const base = normalizedPattern.slice(2); // the part after "*."
|
|
55
|
+
// The base itself must be non-empty.
|
|
56
|
+
if (!base) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
// The hostname must end with ".<base>" — i.e. it has exactly one extra
|
|
60
|
+
// label prepended. We verify this by checking:
|
|
61
|
+
// 1. The hostname ends with ".<base>".
|
|
62
|
+
// 2. After stripping ".<base>" from the right, the remaining prefix
|
|
63
|
+
// contains no dots (so it is exactly one label, not multiple).
|
|
64
|
+
const suffix = "." + base;
|
|
65
|
+
if (!normalizedHost.endsWith(suffix)) {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
const prefix = normalizedHost.slice(0, normalizedHost.length - suffix.length);
|
|
69
|
+
// The prefix must be non-empty (rules out the apex domain itself) and
|
|
70
|
+
// must contain no dots (rules out deeper nesting).
|
|
71
|
+
// Additionally, we guard against non-ASCII characters in the prefix
|
|
72
|
+
// matching a pure ASCII wildcard — the prefix must be composed only of
|
|
73
|
+
// valid ASCII label characters when the base pattern is ASCII-only.
|
|
74
|
+
if (!prefix || prefix.includes(".")) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
// Security guard: if the base pattern is pure ASCII but the prefix
|
|
78
|
+
// contains non-ASCII characters, do not allow the match. This prevents
|
|
79
|
+
// unicode/IDN hostnames from silently satisfying an ASCII wildcard.
|
|
80
|
+
const isBaseAscii = /^[\x00-\x7F]+$/.test(base);
|
|
81
|
+
const isPrefixAscii = /^[\x00-\x7F]+$/.test(prefix);
|
|
82
|
+
if (isBaseAscii && !isPrefixAscii) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
// Exact match.
|
|
88
|
+
return normalizedHost === normalizedPattern;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Return true if the hostname matches at least one pattern in the array.
|
|
92
|
+
* Returns false immediately for an empty patterns array.
|
|
93
|
+
*/
|
|
94
|
+
export function matchesAnyDomain(hostname, patterns) {
|
|
95
|
+
return patterns.some((pattern) => matchesDomain(hostname, pattern));
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=domain-matcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"domain-matcher.js","sourceRoot":"","sources":["../../src/domain-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;GAIG;AACH,SAAS,SAAS,CAAC,KAAa;IAC9B,IAAI,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAC5B,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACpB,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,aAAa,CAAC,QAAgB,EAAE,OAAe;IAC7D,4EAA4E;IAC5E,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,EAAE,CAAC;QAC1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,cAAc,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,iBAAiB,GAAG,SAAS,CAAC,OAAO,CAAC,CAAC;IAE7C,qEAAqE;IACrE,IAAI,CAAC,cAAc,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,yCAAyC;IACzC,IAAI,iBAAiB,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,sBAAsB;QAE/D,qCAAqC;QACrC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,KAAK,CAAC;QACf,CAAC;QAED,uEAAuE;QACvE,gDAAgD;QAChD,yCAAyC;QACzC,sEAAsE;QACtE,oEAAoE;QACpE,MAAM,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC;QAE1B,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACrC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QAE9E,sEAAsE;QACtE,mDAAmD;QACnD,oEAAoE;QACpE,uEAAuE;QACvE,oEAAoE;QACpE,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,mEAAmE;QACnE,wEAAwE;QACxE,oEAAoE;QACpE,MAAM,WAAW,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACpD,IAAI,WAAW,IAAI,CAAC,aAAa,EAAE,CAAC;YAClC,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED,eAAe;IACf,OAAO,cAAc,KAAK,iBAAiB,CAAC;AAC9C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,QAAkB;IACnE,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC;AACtE,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extractor.ts
|
|
3
|
+
*
|
|
4
|
+
* Target Extractor for the MCP Scope Enforcement Proxy.
|
|
5
|
+
*
|
|
6
|
+
* Extracts the target host/IP/domain from a tool call's parameters so that the
|
|
7
|
+
* scope-enforcement layer can decide whether to allow or block the call.
|
|
8
|
+
*
|
|
9
|
+
* SECURITY NOTE: Incorrect extraction means attacking the wrong target.
|
|
10
|
+
* Every code path here has a corresponding unit test — do not modify without
|
|
11
|
+
* updating tests/unit/extractor.test.ts.
|
|
12
|
+
*/
|
|
13
|
+
export interface ExtractionResult {
|
|
14
|
+
/** The extracted target (hostname, IP, CIDR, etc.) — never a full URL. */
|
|
15
|
+
target: string;
|
|
16
|
+
/** The parameter name the target was read from. */
|
|
17
|
+
source: string;
|
|
18
|
+
/** True when the tool was not in the known-tool mapping and the generic
|
|
19
|
+
* fallback parameter list was used instead. */
|
|
20
|
+
usedFallback: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Extract the primary target from a tool call's parameters.
|
|
24
|
+
*
|
|
25
|
+
* @param toolName The MCP tool name as received (case-insensitive).
|
|
26
|
+
* @param params The raw tool parameters object.
|
|
27
|
+
* @returns An ExtractionResult, or null if no target-like parameter was found.
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractTarget(toolName: string, params: Record<string, unknown>): ExtractionResult | null;
|
|
30
|
+
//# sourceMappingURL=extractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.d.ts","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC;IACf,mDAAmD;IACnD,MAAM,EAAE,MAAM,CAAC;IACf;oDACgD;IAChD,YAAY,EAAE,OAAO,CAAC;CACvB;AAsKD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,gBAAgB,GAAG,IAAI,CAmBzB"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* extractor.ts
|
|
3
|
+
*
|
|
4
|
+
* Target Extractor for the MCP Scope Enforcement Proxy.
|
|
5
|
+
*
|
|
6
|
+
* Extracts the target host/IP/domain from a tool call's parameters so that the
|
|
7
|
+
* scope-enforcement layer can decide whether to allow or block the call.
|
|
8
|
+
*
|
|
9
|
+
* SECURITY NOTE: Incorrect extraction means attacking the wrong target.
|
|
10
|
+
* Every code path here has a corresponding unit test — do not modify without
|
|
11
|
+
* updating tests/unit/extractor.test.ts.
|
|
12
|
+
*/
|
|
13
|
+
const TOOL_MAPPINGS = [
|
|
14
|
+
{ match: "nmap", params: ["target", "host", "hosts"] },
|
|
15
|
+
{ match: "nmap_scan", params: ["target", "host", "hosts"] },
|
|
16
|
+
{ match: "burp_scan", params: ["url", "target_url", "base_url"] },
|
|
17
|
+
{ match: "burp_active_scan", params: ["url", "target_url", "base_url"] },
|
|
18
|
+
{ match: "sqlmap", params: ["url", "target"] },
|
|
19
|
+
{ match: "curl", params: ["url", "uri"] },
|
|
20
|
+
{ match: "http_request", params: ["url", "uri"] },
|
|
21
|
+
{ match: "nikto", params: ["host", "target", "url"] },
|
|
22
|
+
{ match: "gobuster", params: ["url", "target"] },
|
|
23
|
+
{ match: "ffuf", params: ["url", "target"] },
|
|
24
|
+
{ match: "dirb", params: ["url", "target"] },
|
|
25
|
+
{ match: "netcat", params: ["host", "target"] },
|
|
26
|
+
{ match: "nc", params: ["host", "target"] },
|
|
27
|
+
{ match: "ping", params: ["host", "target"] },
|
|
28
|
+
{ match: "traceroute", params: ["host", "target"] },
|
|
29
|
+
// Metasploit — prefix match covers msf_exploit, msf_run, msf_payload, etc.
|
|
30
|
+
{ match: "msf_*", params: ["rhost", "rhosts", "target"] },
|
|
31
|
+
{ match: "metasploit", params: ["rhost", "rhosts", "target"] },
|
|
32
|
+
{ match: "nuclei", params: ["target", "targets", "url"] },
|
|
33
|
+
];
|
|
34
|
+
/**
|
|
35
|
+
* Fallback parameter names tried (in priority order) when the tool name does
|
|
36
|
+
* not match any entry in TOOL_MAPPINGS.
|
|
37
|
+
*/
|
|
38
|
+
const FALLBACK_PARAMS = [
|
|
39
|
+
"target",
|
|
40
|
+
"host",
|
|
41
|
+
"url",
|
|
42
|
+
"rhost",
|
|
43
|
+
"destination",
|
|
44
|
+
"uri",
|
|
45
|
+
];
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// URL parsing helpers
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
/**
|
|
50
|
+
* Returns true when the value looks like an http or https URL.
|
|
51
|
+
*/
|
|
52
|
+
function isHttpUrl(value) {
|
|
53
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Given an http/https URL, extract just the hostname (no port, no credentials).
|
|
57
|
+
* Returns null if the URL cannot be parsed.
|
|
58
|
+
*
|
|
59
|
+
* Examples:
|
|
60
|
+
* https://admin:pass@example.com:8443/path → example.com
|
|
61
|
+
* http://[::1]:80/test → ::1
|
|
62
|
+
* http://192.168.1.1/admin → 192.168.1.1
|
|
63
|
+
*/
|
|
64
|
+
function extractHostname(rawUrl) {
|
|
65
|
+
try {
|
|
66
|
+
const parsed = new URL(rawUrl);
|
|
67
|
+
let host = parsed.hostname;
|
|
68
|
+
// Strip IPv6 brackets if present (some Node versions keep them)
|
|
69
|
+
if (host.startsWith("[") && host.endsWith("]")) {
|
|
70
|
+
host = host.slice(1, -1);
|
|
71
|
+
}
|
|
72
|
+
return host.length > 0 ? host : null;
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Parameter value resolution
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
/**
|
|
82
|
+
* Coerce a raw parameter value to a string candidate.
|
|
83
|
+
*
|
|
84
|
+
* - Arrays: take the first element and recurse.
|
|
85
|
+
* - Numbers: convert to string (e.g., numeric IPs are unusual but tolerated).
|
|
86
|
+
* - Strings: return as-is.
|
|
87
|
+
* - Everything else (null, undefined, boolean, object): return null.
|
|
88
|
+
*/
|
|
89
|
+
function coerceToString(value) {
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
if (value.length === 0)
|
|
92
|
+
return null;
|
|
93
|
+
return coerceToString(value[0]);
|
|
94
|
+
}
|
|
95
|
+
if (typeof value === "string") {
|
|
96
|
+
return value;
|
|
97
|
+
}
|
|
98
|
+
if (typeof value === "number") {
|
|
99
|
+
return String(value);
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Given a raw param value, return the resolved target string.
|
|
105
|
+
*
|
|
106
|
+
* - If the value is a URL (http/https), extract the hostname.
|
|
107
|
+
* - Otherwise return the coerced string directly.
|
|
108
|
+
* - Returns null for empty strings or unparseable URLs.
|
|
109
|
+
*/
|
|
110
|
+
function resolveParamValue(value) {
|
|
111
|
+
const raw = coerceToString(value);
|
|
112
|
+
if (raw === null || raw.trim() === "")
|
|
113
|
+
return null;
|
|
114
|
+
if (isHttpUrl(raw)) {
|
|
115
|
+
return extractHostname(raw);
|
|
116
|
+
}
|
|
117
|
+
return raw;
|
|
118
|
+
}
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// Tool-name matching
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
/**
|
|
123
|
+
* Find the candidate parameter list for a given tool name.
|
|
124
|
+
* Returns null when no mapping is found (caller should use fallback).
|
|
125
|
+
*
|
|
126
|
+
* Matching is case-insensitive.
|
|
127
|
+
* Supports prefix wildcards (e.g. "msf_*" matches "msf_exploit").
|
|
128
|
+
*/
|
|
129
|
+
function findMapping(toolName) {
|
|
130
|
+
const lower = toolName.toLowerCase();
|
|
131
|
+
for (const mapping of TOOL_MAPPINGS) {
|
|
132
|
+
const pattern = mapping.match;
|
|
133
|
+
if (pattern.endsWith("*")) {
|
|
134
|
+
// Prefix match: e.g. "msf_*" → prefix "msf_"
|
|
135
|
+
const prefix = pattern.slice(0, -1);
|
|
136
|
+
if (lower.startsWith(prefix)) {
|
|
137
|
+
return mapping.params;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
if (lower === pattern) {
|
|
142
|
+
return mapping.params;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// Public API
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
/**
|
|
152
|
+
* Extract the primary target from a tool call's parameters.
|
|
153
|
+
*
|
|
154
|
+
* @param toolName The MCP tool name as received (case-insensitive).
|
|
155
|
+
* @param params The raw tool parameters object.
|
|
156
|
+
* @returns An ExtractionResult, or null if no target-like parameter was found.
|
|
157
|
+
*/
|
|
158
|
+
export function extractTarget(toolName, params) {
|
|
159
|
+
const knownParams = findMapping(toolName);
|
|
160
|
+
const usedFallback = knownParams === null;
|
|
161
|
+
const candidates = knownParams ?? FALLBACK_PARAMS;
|
|
162
|
+
for (const paramName of candidates) {
|
|
163
|
+
if (!(paramName in params))
|
|
164
|
+
continue;
|
|
165
|
+
const resolved = resolveParamValue(params[paramName]);
|
|
166
|
+
if (resolved === null)
|
|
167
|
+
continue;
|
|
168
|
+
return {
|
|
169
|
+
target: resolved,
|
|
170
|
+
source: paramName,
|
|
171
|
+
usedFallback,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=extractor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extractor.js","sourceRoot":"","sources":["../../src/extractor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ScopeEnforcementProxy } from "./proxy.js";
|
|
2
|
+
export { ScopeValidator } from "./validator.js";
|
|
3
|
+
export { loadManifest } from "./manifest.js";
|
|
4
|
+
export { loadConfig } from "./config.js";
|
|
5
|
+
export { AuditLogger } from "./audit/index.js";
|
|
6
|
+
export type { ScopeManifest, AuditEntry, ValidationResult, Decision } from "./types.js";
|
|
7
|
+
export declare const VERSION = "0.1.0";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACxF,eAAO,MAAM,OAAO,UAAU,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { ScopeEnforcementProxy } from "./proxy.js";
|
|
2
|
+
export { ScopeValidator } from "./validator.js";
|
|
3
|
+
export { loadManifest } from "./manifest.js";
|
|
4
|
+
export { loadConfig } from "./config.js";
|
|
5
|
+
export { AuditLogger } from "./audit/index.js";
|
|
6
|
+
export const VERSION = "0.1.0";
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ip-matcher.ts
|
|
3
|
+
*
|
|
4
|
+
* IP / CIDR matching utilities for scope enforcement.
|
|
5
|
+
* Used to determine whether a target IP is in-scope, private, or a cloud
|
|
6
|
+
* metadata endpoint. This is security-critical code: every edge case matters.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Check whether `ip` falls within the CIDR `cidr`.
|
|
10
|
+
*
|
|
11
|
+
* - Bare IPs (no slash) are treated as an exact-host match (/32 or /128).
|
|
12
|
+
* - Returns `false` for any invalid input rather than throwing.
|
|
13
|
+
* - An IPv4 address will never match an IPv6 range and vice-versa.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isIpInCidr(ip: string, cidr: string): boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Check whether `ip` falls within any of the provided CIDR/IP `ranges`.
|
|
18
|
+
*
|
|
19
|
+
* - An empty `ranges` array always returns `false`.
|
|
20
|
+
* - Invalid individual ranges are silently skipped.
|
|
21
|
+
* - Returns `false` for any invalid `ip`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isIpInAnyRange(ip: string, ranges: string[]): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Return true if `ip` is a private/link-local IPv4 address as defined by
|
|
26
|
+
* RFC 1918 and RFC 3927 (169.254.0.0/16).
|
|
27
|
+
*
|
|
28
|
+
* Returns `false` for invalid inputs and for IPv6 addresses.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isRfc1918(ip: string): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Return true if `ip` is a known cloud metadata endpoint.
|
|
33
|
+
*
|
|
34
|
+
* Performs exact-host matching only — no subnet expansion.
|
|
35
|
+
* Returns `false` for invalid inputs.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isCloudMetadata(ip: string): boolean;
|
|
38
|
+
//# sourceMappingURL=ip-matcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ip-matcher.d.ts","sourceRoot":"","sources":["../../src/ip-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAuCH;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAiB5D;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAOpE;AAgBD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAS7C;AAYD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAKnD"}
|