@securecode-ai/mcp 0.4.0 → 0.4.1

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.
Files changed (56) hide show
  1. package/README.md +107 -13
  2. package/dist/api/client.d.ts +1 -1
  3. package/dist/api/client.js +2 -1
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/attack/agentScanExecutor.js +159 -5
  6. package/dist/attack/agentScanExecutor.js.map +1 -1
  7. package/dist/attack/agentScanLoop.js +157 -3
  8. package/dist/attack/agentScanLoop.js.map +1 -1
  9. package/dist/attack/agentScanProtocol.d.ts +47 -5
  10. package/dist/attack/agentScanProtocol.js +3 -3
  11. package/dist/index.js +218 -0
  12. package/dist/index.js.map +1 -1
  13. package/dist/mcp/server.js +5 -0
  14. package/dist/mcp/server.js.map +1 -1
  15. package/dist/mcp/tools.js +80 -3
  16. package/dist/mcp/tools.js.map +1 -1
  17. package/dist/project-map/agentMemory.d.ts +75 -0
  18. package/dist/project-map/agentMemory.js +230 -0
  19. package/dist/project-map/agentMemory.js.map +1 -0
  20. package/dist/project-map/crossFileTaintTracker.d.ts +51 -0
  21. package/dist/project-map/crossFileTaintTracker.js +429 -0
  22. package/dist/project-map/crossFileTaintTracker.js.map +1 -0
  23. package/dist/project-map/endpointDiscovery.d.ts +24 -0
  24. package/dist/project-map/endpointDiscovery.js +101 -0
  25. package/dist/project-map/endpointDiscovery.js.map +1 -0
  26. package/dist/project-map/guardEvaluator.js +37 -0
  27. package/dist/project-map/guardEvaluator.js.map +1 -1
  28. package/dist/project-map/guardPatterns.js +16 -5
  29. package/dist/project-map/guardPatterns.js.map +1 -1
  30. package/dist/project-map/sanitizers.js +10 -0
  31. package/dist/project-map/sanitizers.js.map +1 -1
  32. package/dist/project-map/scanCache.d.ts +67 -0
  33. package/dist/project-map/scanCache.js +169 -0
  34. package/dist/project-map/scanCache.js.map +1 -0
  35. package/dist/project-map/sinkRegistry.js +165 -0
  36. package/dist/project-map/sinkRegistry.js.map +1 -1
  37. package/dist/project-map/taintSources.d.ts +19 -1
  38. package/dist/project-map/taintSources.js +69 -2
  39. package/dist/project-map/taintSources.js.map +1 -1
  40. package/dist/project-map/taintTracker.d.ts +4 -1
  41. package/dist/project-map/taintTracker.js +188 -5
  42. package/dist/project-map/taintTracker.js.map +1 -1
  43. package/dist/tools/agentMemoryTools.d.ts +18 -0
  44. package/dist/tools/agentMemoryTools.js +107 -0
  45. package/dist/tools/agentMemoryTools.js.map +1 -0
  46. package/dist/tools/agentScan.js +206 -33
  47. package/dist/tools/agentScan.js.map +1 -1
  48. package/dist/utils/files.js +19 -2
  49. package/dist/utils/files.js.map +1 -1
  50. package/dist/utils/listFiles.d.ts +17 -0
  51. package/dist/utils/listFiles.js +126 -0
  52. package/dist/utils/listFiles.js.map +1 -0
  53. package/dist/utils/listImports.d.ts +15 -0
  54. package/dist/utils/listImports.js +164 -0
  55. package/dist/utils/listImports.js.map +1 -0
  56. package/package.json +1 -1
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Agent memory — per-workspace store of false positives and known facts.
3
+ *
4
+ * The agent reads this at the start of each scan so it doesn't repeat
5
+ * mistakes from prior scans. False positives are patterns the user has
6
+ * explicitly dismissed; known facts are structural facts about the project
7
+ * (e.g. "uses requireMembership for auth") that speed up investigation.
8
+ *
9
+ * Storage: <workspaceRoot>/.securecode/agent-memory.json
10
+ * Pattern: same as scanCache.ts — lazy mkdir, atomic write (.tmp + rename).
11
+ *
12
+ * Privacy: per-workspace only. No cross-tenant leakage. User-owned, deletable.
13
+ */
14
+ export interface FalsePositiveEntry {
15
+ id: string;
16
+ findingType: string;
17
+ file: string;
18
+ line: number;
19
+ /** SHA-256 of the evidence string — for dedup. */
20
+ evidenceHash: string;
21
+ /** Short pattern description for the prompt. */
22
+ pattern: string;
23
+ /** User's reason for dismissing. */
24
+ reason: string;
25
+ /** Code snippet (truncated) for context. */
26
+ codeSnippet?: string;
27
+ addedAt: string;
28
+ }
29
+ export interface KnownFactEntry {
30
+ id: string;
31
+ fact: string;
32
+ source: string;
33
+ addedAt: string;
34
+ }
35
+ export interface AgentMemory {
36
+ version: number;
37
+ falsePositives: FalsePositiveEntry[];
38
+ knownFacts: KnownFactEntry[];
39
+ }
40
+ /**
41
+ * Load agent memory for a workspace. Returns an empty memory object
42
+ * (version + empty arrays) if the file doesn't exist or is corrupt.
43
+ */
44
+ export declare function loadAgentMemory(workspaceRoot: string): AgentMemory;
45
+ export interface RecordFalsePositiveInput {
46
+ filePath: string;
47
+ findingType: string;
48
+ line: number;
49
+ evidence: string;
50
+ reason: string;
51
+ pattern?: string;
52
+ codeSnippet?: string;
53
+ }
54
+ /**
55
+ * Record a false positive. Dedupes by (findingType + evidenceHash).
56
+ * Returns the entry (existing or new). Returns null if input is invalid.
57
+ */
58
+ export declare function recordFalsePositive(workspaceRoot: string, input: RecordFalsePositiveInput): FalsePositiveEntry | null;
59
+ /**
60
+ * Remove a false positive by ID. Returns true if removed.
61
+ */
62
+ export declare function removeFalsePositive(workspaceRoot: string, id: string): boolean;
63
+ /**
64
+ * Add a known fact. Dedupes by fact text (case-insensitive).
65
+ */
66
+ export declare function addKnownFact(workspaceRoot: string, fact: string, source: string): KnownFactEntry | null;
67
+ /**
68
+ * Clear all agent memory (false positives + known facts) for a workspace.
69
+ */
70
+ export declare function clearAgentMemory(workspaceRoot: string): boolean;
71
+ /**
72
+ * Format agent memory into a string block for injection into the agent's
73
+ * target context. Returns empty string if no memory.
74
+ */
75
+ export declare function formatMemoryForPrompt(memory: AgentMemory): string;
@@ -0,0 +1,230 @@
1
+ "use strict";
2
+ /**
3
+ * Agent memory — per-workspace store of false positives and known facts.
4
+ *
5
+ * The agent reads this at the start of each scan so it doesn't repeat
6
+ * mistakes from prior scans. False positives are patterns the user has
7
+ * explicitly dismissed; known facts are structural facts about the project
8
+ * (e.g. "uses requireMembership for auth") that speed up investigation.
9
+ *
10
+ * Storage: <workspaceRoot>/.securecode/agent-memory.json
11
+ * Pattern: same as scanCache.ts — lazy mkdir, atomic write (.tmp + rename).
12
+ *
13
+ * Privacy: per-workspace only. No cross-tenant leakage. User-owned, deletable.
14
+ */
15
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ var desc = Object.getOwnPropertyDescriptor(m, k);
18
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
19
+ desc = { enumerable: true, get: function() { return m[k]; } };
20
+ }
21
+ Object.defineProperty(o, k2, desc);
22
+ }) : (function(o, m, k, k2) {
23
+ if (k2 === undefined) k2 = k;
24
+ o[k2] = m[k];
25
+ }));
26
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
27
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
28
+ }) : function(o, v) {
29
+ o["default"] = v;
30
+ });
31
+ var __importStar = (this && this.__importStar) || (function () {
32
+ var ownKeys = function(o) {
33
+ ownKeys = Object.getOwnPropertyNames || function (o) {
34
+ var ar = [];
35
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
36
+ return ar;
37
+ };
38
+ return ownKeys(o);
39
+ };
40
+ return function (mod) {
41
+ if (mod && mod.__esModule) return mod;
42
+ var result = {};
43
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
44
+ __setModuleDefault(result, mod);
45
+ return result;
46
+ };
47
+ })();
48
+ Object.defineProperty(exports, "__esModule", { value: true });
49
+ exports.loadAgentMemory = loadAgentMemory;
50
+ exports.recordFalsePositive = recordFalsePositive;
51
+ exports.removeFalsePositive = removeFalsePositive;
52
+ exports.addKnownFact = addKnownFact;
53
+ exports.clearAgentMemory = clearAgentMemory;
54
+ exports.formatMemoryForPrompt = formatMemoryForPrompt;
55
+ const fs = __importStar(require("fs"));
56
+ const path = __importStar(require("path"));
57
+ const crypto = __importStar(require("crypto"));
58
+ const MEMORY_DIR = '.securecode';
59
+ const MEMORY_FILE = 'agent-memory.json';
60
+ const MEMORY_VERSION = 1;
61
+ const MAX_FALSE_POSITIVES = 100; // cap to prevent unbounded growth
62
+ const MAX_KNOWN_FACTS = 50;
63
+ // ── Path helpers ────────────────────────────────────────────────────────────
64
+ function memoryPath(workspaceRoot) {
65
+ return path.join(workspaceRoot, MEMORY_DIR, MEMORY_FILE);
66
+ }
67
+ function hashEvidence(evidence) {
68
+ return crypto.createHash('sha256').update(evidence).digest('hex').slice(0, 16);
69
+ }
70
+ function genId() {
71
+ return 'fp_' + crypto.randomBytes(4).toString('hex');
72
+ }
73
+ // ── Read / Write ────────────────────────────────────────────────────────────
74
+ /**
75
+ * Load agent memory for a workspace. Returns an empty memory object
76
+ * (version + empty arrays) if the file doesn't exist or is corrupt.
77
+ */
78
+ function loadAgentMemory(workspaceRoot) {
79
+ const p = memoryPath(workspaceRoot);
80
+ try {
81
+ if (!fs.existsSync(p)) {
82
+ return { version: MEMORY_VERSION, falsePositives: [], knownFacts: [] };
83
+ }
84
+ const raw = fs.readFileSync(p, 'utf8');
85
+ const data = JSON.parse(raw);
86
+ if (!data.version || data.version > MEMORY_VERSION) {
87
+ // Forward-incompatible — start fresh
88
+ return { version: MEMORY_VERSION, falsePositives: [], knownFacts: [] };
89
+ }
90
+ return {
91
+ version: MEMORY_VERSION,
92
+ falsePositives: data.falsePositives || [],
93
+ knownFacts: data.knownFacts || [],
94
+ };
95
+ }
96
+ catch {
97
+ return { version: MEMORY_VERSION, falsePositives: [], knownFacts: [] };
98
+ }
99
+ }
100
+ /** Save agent memory (atomic write). */
101
+ function saveAgentMemory(workspaceRoot, memory) {
102
+ const dir = path.join(workspaceRoot, MEMORY_DIR);
103
+ if (!fs.existsSync(dir)) {
104
+ fs.mkdirSync(dir, { recursive: true });
105
+ }
106
+ const p = memoryPath(workspaceRoot);
107
+ const tmp = p + '.tmp';
108
+ fs.writeFileSync(tmp, JSON.stringify(memory, null, 2), 'utf8');
109
+ fs.renameSync(tmp, p);
110
+ }
111
+ /**
112
+ * Record a false positive. Dedupes by (findingType + evidenceHash).
113
+ * Returns the entry (existing or new). Returns null if input is invalid.
114
+ */
115
+ function recordFalsePositive(workspaceRoot, input) {
116
+ if (!input.filePath || !input.findingType || !input.evidence || !input.reason) {
117
+ return null;
118
+ }
119
+ const memory = loadAgentMemory(workspaceRoot);
120
+ const evidenceHash = hashEvidence(input.evidence);
121
+ // Dedup: if the same finding type + evidence hash exists, update the reason
122
+ const existingIdx = memory.falsePositives.findIndex(fp => fp.findingType === input.findingType && fp.evidenceHash === evidenceHash);
123
+ if (existingIdx >= 0) {
124
+ memory.falsePositives[existingIdx].reason = input.reason;
125
+ memory.falsePositives[existingIdx].pattern = input.pattern || memory.falsePositives[existingIdx].pattern;
126
+ saveAgentMemory(workspaceRoot, memory);
127
+ return memory.falsePositives[existingIdx];
128
+ }
129
+ const entry = {
130
+ id: genId(),
131
+ findingType: input.findingType,
132
+ file: input.filePath,
133
+ line: input.line,
134
+ evidenceHash,
135
+ pattern: input.pattern || input.evidence.slice(0, 200),
136
+ reason: input.reason,
137
+ codeSnippet: input.codeSnippet ? input.codeSnippet.slice(0, 500) : undefined,
138
+ addedAt: new Date().toISOString(),
139
+ };
140
+ memory.falsePositives.push(entry);
141
+ // Cap growth — drop oldest
142
+ if (memory.falsePositives.length > MAX_FALSE_POSITIVES) {
143
+ memory.falsePositives = memory.falsePositives.slice(-MAX_FALSE_POSITIVES);
144
+ }
145
+ saveAgentMemory(workspaceRoot, memory);
146
+ return entry;
147
+ }
148
+ /**
149
+ * Remove a false positive by ID. Returns true if removed.
150
+ */
151
+ function removeFalsePositive(workspaceRoot, id) {
152
+ const memory = loadAgentMemory(workspaceRoot);
153
+ const before = memory.falsePositives.length;
154
+ memory.falsePositives = memory.falsePositives.filter(fp => fp.id !== id);
155
+ if (memory.falsePositives.length === before)
156
+ return false;
157
+ saveAgentMemory(workspaceRoot, memory);
158
+ return true;
159
+ }
160
+ /**
161
+ * Add a known fact. Dedupes by fact text (case-insensitive).
162
+ */
163
+ function addKnownFact(workspaceRoot, fact, source) {
164
+ if (!fact || !source)
165
+ return null;
166
+ const memory = loadAgentMemory(workspaceRoot);
167
+ const lower = fact.toLowerCase().trim();
168
+ if (memory.knownFacts.some(kf => kf.fact.toLowerCase().trim() === lower)) {
169
+ return null; // already exists
170
+ }
171
+ const entry = {
172
+ id: 'fact_' + crypto.randomBytes(4).toString('hex'),
173
+ fact,
174
+ source,
175
+ addedAt: new Date().toISOString(),
176
+ };
177
+ memory.knownFacts.push(entry);
178
+ if (memory.knownFacts.length > MAX_KNOWN_FACTS) {
179
+ memory.knownFacts = memory.knownFacts.slice(-MAX_KNOWN_FACTS);
180
+ }
181
+ saveAgentMemory(workspaceRoot, memory);
182
+ return entry;
183
+ }
184
+ /**
185
+ * Clear all agent memory (false positives + known facts) for a workspace.
186
+ */
187
+ function clearAgentMemory(workspaceRoot) {
188
+ const p = memoryPath(workspaceRoot);
189
+ try {
190
+ if (fs.existsSync(p)) {
191
+ fs.unlinkSync(p);
192
+ return true;
193
+ }
194
+ return false;
195
+ }
196
+ catch {
197
+ return false;
198
+ }
199
+ }
200
+ // ── Prompt formatting ───────────────────────────────────────────────────────
201
+ /**
202
+ * Format agent memory into a string block for injection into the agent's
203
+ * target context. Returns empty string if no memory.
204
+ */
205
+ function formatMemoryForPrompt(memory) {
206
+ const hasFps = memory.falsePositives.length > 0;
207
+ const hasFacts = memory.knownFacts.length > 0;
208
+ if (!hasFps && !hasFacts)
209
+ return '';
210
+ const lines = ['Workspace memory (from previous scans in this workspace):'];
211
+ if (hasFps) {
212
+ lines.push('', `False positives — DO NOT report similar patterns (${memory.falsePositives.length}):`);
213
+ memory.falsePositives.forEach((fp, i) => {
214
+ lines.push(` ${i + 1}. [${fp.findingType}] "${fp.pattern}"`);
215
+ lines.push(` Reason: ${fp.reason}`);
216
+ if (fp.file)
217
+ lines.push(` Was at: ${fp.file}:${fp.line}`);
218
+ });
219
+ lines.push('', 'Before reporting a finding, check if it matches any false positive above.');
220
+ lines.push('If the finding type AND code pattern match a known FP, do NOT report it.');
221
+ }
222
+ if (hasFacts) {
223
+ lines.push('', `Known facts about this project (${memory.knownFacts.length}):`);
224
+ memory.knownFacts.forEach((f, i) => {
225
+ lines.push(` ${i + 1}. ${f.fact} (source: ${f.source})`);
226
+ });
227
+ }
228
+ return lines.join('\n');
229
+ }
230
+ //# sourceMappingURL=agentMemory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentMemory.js","sourceRoot":"","sources":["../../src/project-map/agentMemory.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;GAYG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+DH,0CAoBC;AA8BD,kDA2CC;AAKD,kDAOC;AAKD,oCAuBC;AAKD,4CAWC;AAQD,sDA0BC;AApPD,uCAAyB;AACzB,2CAA6B;AAC7B,+CAAiC;AAEjC,MAAM,UAAU,GAAG,aAAa,CAAC;AACjC,MAAM,WAAW,GAAG,mBAAmB,CAAC;AACxC,MAAM,cAAc,GAAG,CAAC,CAAC;AACzB,MAAM,mBAAmB,GAAG,GAAG,CAAC,CAAE,kCAAkC;AACpE,MAAM,eAAe,GAAG,EAAE,CAAC;AAiC3B,+EAA+E;AAE/E,SAAS,UAAU,CAAC,aAAqB;IACrC,OAAO,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC;AAC7D,CAAC;AAED,SAAS,YAAY,CAAC,QAAgB;IAClC,OAAO,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,SAAS,KAAK;IACV,OAAO,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AACzD,CAAC;AAED,+EAA+E;AAE/E;;;GAGG;AACH,SAAgB,eAAe,CAAC,aAAqB;IACjD,MAAM,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACpC,IAAI,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACpB,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC3E,CAAC;QACD,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAgB,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,GAAG,cAAc,EAAE,CAAC;YACjD,qCAAqC;YACrC,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;QAC3E,CAAC;QACD,OAAO;YACH,OAAO,EAAE,cAAc;YACvB,cAAc,EAAE,IAAI,CAAC,cAAc,IAAI,EAAE;YACzC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,EAAE;SACpC,CAAC;IACN,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;IAC3E,CAAC;AACL,CAAC;AAED,wCAAwC;AACxC,SAAS,eAAe,CAAC,aAAqB,EAAE,MAAmB;IAC/D,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACtB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;IACD,MAAM,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,CAAC,GAAG,MAAM,CAAC;IACvB,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;IAC/D,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;AAC1B,CAAC;AAcD;;;GAGG;AACH,SAAgB,mBAAmB,CAC/B,aAAqB,EACrB,KAA+B;IAE/B,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,CAAC,KAAK,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5E,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAC9C,MAAM,YAAY,GAAG,YAAY,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IAElD,4EAA4E;IAC5E,MAAM,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,SAAS,CAC/C,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,WAAW,KAAK,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,YAAY,KAAK,YAAY,CACjF,CAAC;IACF,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;QACnB,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QACzD,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,OAAO,GAAG,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC,OAAO,CAAC;QACzG,eAAe,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;QACvC,OAAO,MAAM,CAAC,cAAc,CAAC,WAAW,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,KAAK,GAAuB;QAC9B,EAAE,EAAE,KAAK,EAAE;QACX,WAAW,EAAE,KAAK,CAAC,WAAW;QAC9B,IAAI,EAAE,KAAK,CAAC,QAAQ;QACpB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,YAAY;QACZ,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;QACtD,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,WAAW,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;QAC5E,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IAEF,MAAM,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAElC,2BAA2B;IAC3B,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,mBAAmB,EAAE,CAAC;QACrD,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,CAAC;IAC9E,CAAC;IAED,eAAe,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAgB,mBAAmB,CAAC,aAAqB,EAAE,EAAU;IACjE,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC;IAC5C,MAAM,CAAC,cAAc,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,IAAI,MAAM,CAAC,cAAc,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1D,eAAe,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAgB,YAAY,CACxB,aAAqB,EACrB,IAAY,EACZ,MAAc;IAEd,IAAI,CAAC,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,MAAM,GAAG,eAAe,CAAC,aAAa,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IACxC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,KAAK,CAAC,EAAE,CAAC;QACvE,OAAO,IAAI,CAAC,CAAE,iBAAiB;IACnC,CAAC;IACD,MAAM,KAAK,GAAmB;QAC1B,EAAE,EAAE,OAAO,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnD,IAAI;QACJ,MAAM;QACN,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACpC,CAAC;IACF,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,eAAe,EAAE,CAAC;QAC7C,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,eAAe,CAAC,CAAC;IAClE,CAAC;IACD,eAAe,CAAC,aAAa,EAAE,MAAM,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,aAAqB;IAClD,MAAM,CAAC,GAAG,UAAU,CAAC,aAAa,CAAC,CAAC;IACpC,IAAI,CAAC;QACD,IAAI,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;YACnB,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,KAAK,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,KAAK,CAAC;IACjB,CAAC;AACL,CAAC;AAED,+EAA+E;AAE/E;;;GAGG;AACH,SAAgB,qBAAqB,CAAC,MAAmB;IACrD,MAAM,MAAM,GAAG,MAAM,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;IAC9C,IAAI,CAAC,MAAM,IAAI,CAAC,QAAQ;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAa,CAAC,2DAA2D,CAAC,CAAC;IAEtF,IAAI,MAAM,EAAE,CAAC;QACT,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,qDAAqD,MAAM,CAAC,cAAc,CAAC,MAAM,IAAI,CAAC,CAAC;QACtG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;YACpC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,WAAW,MAAM,EAAE,CAAC,OAAO,GAAG,CAAC,CAAC;YAC9D,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC;YACxC,IAAI,EAAE,CAAC,IAAI;gBAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,2EAA2E,CAAC,CAAC;QAC5F,KAAK,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;IAC3F,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACX,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,mCAAmC,MAAM,CAAC,UAAU,CAAC,MAAM,IAAI,CAAC,CAAC;QAChF,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC/B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Cross-file taint tracker — follows taint across file boundaries.
3
+ *
4
+ * The single-file `trackTaint` engine finds source→sink flows within one
5
+ * file. This module extends that to multi-file flows by:
6
+ *
7
+ * 1. Parsing the entry file's imports (collectImports)
8
+ * 2. Resolving each import to a file on disk (resolveModulePath)
9
+ * 3. Indexing each imported function: does it return tainted data?
10
+ * Does it propagate taint through a specific parameter?
11
+ * 4. Running taint tracking on the entry file with the cross-file
12
+ * function index, so calls to imported functions that propagate
13
+ * taint are recognised.
14
+ *
15
+ * Limits prevent runaway analysis on large codebases:
16
+ * maxDepth (3) — how many import hops to follow
17
+ * maxFiles (10) — total files parsed per trace
18
+ * maxFunctionBodySize (5000 chars) — skip oversized functions
19
+ */
20
+ export interface CrossFileStep {
21
+ file: string;
22
+ line: number;
23
+ variable: string;
24
+ operation: 'source' | 'call-cross-file' | 'return-tainted' | 'sink-arg';
25
+ description: string;
26
+ }
27
+ export interface CrossFileTaintResult {
28
+ source: string;
29
+ sourceLine: number;
30
+ sourceFile: string;
31
+ sink: string;
32
+ sinkLine: number;
33
+ sinkFile: string;
34
+ canonicalType: string;
35
+ crossFileSteps: CrossFileStep[];
36
+ }
37
+ export interface CrossFileTaintOptions {
38
+ workspaceRoot: string;
39
+ filePath: string;
40
+ maxDepth?: number;
41
+ maxFiles?: number;
42
+ }
43
+ /**
44
+ * Track taint propagation across file boundaries.
45
+ *
46
+ * Parses the entry file, resolves its imports, indexes imported functions
47
+ * for taint behavior, then runs taint tracking with cross-file knowledge.
48
+ *
49
+ * Returns CrossFileTaintResult[] with full file:line paths.
50
+ */
51
+ export declare function trackTaintCrossFile(opts: CrossFileTaintOptions): Promise<CrossFileTaintResult[]>;