dravix-agent 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/.claude/settings.example.json +30 -0
- package/ARCHITECTURE.md +410 -0
- package/LICENSE +21 -0
- package/README.md +153 -0
- package/ROADMAP.md +117 -0
- package/data/vulnkb.json +666 -0
- package/dist/bin/aegis.d.ts +3 -0
- package/dist/bin/aegis.d.ts.map +1 -0
- package/dist/bin/aegis.js +489 -0
- package/dist/bin/aegis.js.map +1 -0
- package/dist/cache.d.ts +9 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +146 -0
- package/dist/cache.js.map +1 -0
- package/dist/engines/ai-sinks.d.ts +52 -0
- package/dist/engines/ai-sinks.d.ts.map +1 -0
- package/dist/engines/ai-sinks.js +204 -0
- package/dist/engines/ai-sinks.js.map +1 -0
- package/dist/engines/eslint.d.ts +9 -0
- package/dist/engines/eslint.d.ts.map +1 -0
- package/dist/engines/eslint.js +245 -0
- package/dist/engines/eslint.js.map +1 -0
- package/dist/engines/joern.d.ts +3 -0
- package/dist/engines/joern.d.ts.map +1 -0
- package/dist/engines/joern.js +98 -0
- package/dist/engines/joern.js.map +1 -0
- package/dist/engines/js-sinks.d.ts +70 -0
- package/dist/engines/js-sinks.d.ts.map +1 -0
- package/dist/engines/js-sinks.js +370 -0
- package/dist/engines/js-sinks.js.map +1 -0
- package/dist/engines/llm-critic.d.ts +130 -0
- package/dist/engines/llm-critic.d.ts.map +1 -0
- package/dist/engines/llm-critic.js +551 -0
- package/dist/engines/llm-critic.js.map +1 -0
- package/dist/engines/pragma.d.ts +20 -0
- package/dist/engines/pragma.d.ts.map +1 -0
- package/dist/engines/pragma.js +83 -0
- package/dist/engines/pragma.js.map +1 -0
- package/dist/engines/property-test.d.ts +3 -0
- package/dist/engines/property-test.d.ts.map +1 -0
- package/dist/engines/property-test.js +134 -0
- package/dist/engines/property-test.js.map +1 -0
- package/dist/engines/pyright.d.ts +10 -0
- package/dist/engines/pyright.d.ts.map +1 -0
- package/dist/engines/pyright.js +143 -0
- package/dist/engines/pyright.js.map +1 -0
- package/dist/engines/pysa.d.ts +3 -0
- package/dist/engines/pysa.d.ts.map +1 -0
- package/dist/engines/pysa.js +83 -0
- package/dist/engines/pysa.js.map +1 -0
- package/dist/engines/python-sinks.d.ts +82 -0
- package/dist/engines/python-sinks.d.ts.map +1 -0
- package/dist/engines/python-sinks.js +459 -0
- package/dist/engines/python-sinks.js.map +1 -0
- package/dist/engines/registry.d.ts +26 -0
- package/dist/engines/registry.d.ts.map +1 -0
- package/dist/engines/registry.js +70 -0
- package/dist/engines/registry.js.map +1 -0
- package/dist/engines/secret-scan.d.ts +22 -0
- package/dist/engines/secret-scan.d.ts.map +1 -0
- package/dist/engines/secret-scan.js +179 -0
- package/dist/engines/secret-scan.js.map +1 -0
- package/dist/engines/semgrep.d.ts +10 -0
- package/dist/engines/semgrep.d.ts.map +1 -0
- package/dist/engines/semgrep.js +200 -0
- package/dist/engines/semgrep.js.map +1 -0
- package/dist/engines/treesitter.d.ts +18 -0
- package/dist/engines/treesitter.d.ts.map +1 -0
- package/dist/engines/treesitter.js +135 -0
- package/dist/engines/treesitter.js.map +1 -0
- package/dist/engines/tsc.d.ts +10 -0
- package/dist/engines/tsc.d.ts.map +1 -0
- package/dist/engines/tsc.js +142 -0
- package/dist/engines/tsc.js.map +1 -0
- package/dist/engines/types.d.ts +47 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +27 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/findings.d.ts +121 -0
- package/dist/findings.d.ts.map +1 -0
- package/dist/findings.js +98 -0
- package/dist/findings.js.map +1 -0
- package/dist/hooks/claude-code.d.ts +3 -0
- package/dist/hooks/claude-code.d.ts.map +1 -0
- package/dist/hooks/claude-code.js +187 -0
- package/dist/hooks/claude-code.js.map +1 -0
- package/dist/index/context.d.ts +127 -0
- package/dist/index/context.d.ts.map +1 -0
- package/dist/index/context.js +267 -0
- package/dist/index/context.js.map +1 -0
- package/dist/index/embeddings.d.ts +68 -0
- package/dist/index/embeddings.d.ts.map +1 -0
- package/dist/index/embeddings.js +570 -0
- package/dist/index/embeddings.js.map +1 -0
- package/dist/index/graph_routing.d.ts +36 -0
- package/dist/index/graph_routing.d.ts.map +1 -0
- package/dist/index/graph_routing.js +170 -0
- package/dist/index/graph_routing.js.map +1 -0
- package/dist/index/joern.d.ts +76 -0
- package/dist/index/joern.d.ts.map +1 -0
- package/dist/index/joern.js +782 -0
- package/dist/index/joern.js.map +1 -0
- package/dist/index/property-test.d.ts +88 -0
- package/dist/index/property-test.d.ts.map +1 -0
- package/dist/index/property-test.js +466 -0
- package/dist/index/property-test.js.map +1 -0
- package/dist/index/proto/scip.proto +897 -0
- package/dist/index/pysa.d.ts +91 -0
- package/dist/index/pysa.d.ts.map +1 -0
- package/dist/index/pysa.js +617 -0
- package/dist/index/pysa.js.map +1 -0
- package/dist/index/scip.d.ts +76 -0
- package/dist/index/scip.d.ts.map +1 -0
- package/dist/index/scip.js +541 -0
- package/dist/index/scip.js.map +1 -0
- package/dist/index/vulrag.d.ts +86 -0
- package/dist/index/vulrag.d.ts.map +1 -0
- package/dist/index/vulrag.js +242 -0
- package/dist/index/vulrag.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/install/claude-code.d.ts +31 -0
- package/dist/install/claude-code.d.ts.map +1 -0
- package/dist/install/claude-code.js +447 -0
- package/dist/install/claude-code.js.map +1 -0
- package/dist/lang.d.ts +5 -0
- package/dist/lang.d.ts.map +1 -0
- package/dist/lang.js +52 -0
- package/dist/lang.js.map +1 -0
- package/dist/learning/suppressions.d.ts +70 -0
- package/dist/learning/suppressions.d.ts.map +1 -0
- package/dist/learning/suppressions.js +179 -0
- package/dist/learning/suppressions.js.map +1 -0
- package/dist/mcp/server.d.ts +2 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +187 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/explain.d.ts +58 -0
- package/dist/mcp/tools/explain.d.ts.map +1 -0
- package/dist/mcp/tools/explain.js +60 -0
- package/dist/mcp/tools/explain.js.map +1 -0
- package/dist/mcp/tools/precheck.d.ts +29 -0
- package/dist/mcp/tools/precheck.d.ts.map +1 -0
- package/dist/mcp/tools/precheck.js +42 -0
- package/dist/mcp/tools/precheck.js.map +1 -0
- package/dist/mcp/tools/validate.d.ts +73 -0
- package/dist/mcp/tools/validate.d.ts.map +1 -0
- package/dist/mcp/tools/validate.js +66 -0
- package/dist/mcp/tools/validate.js.map +1 -0
- package/dist/mcp/warm.d.ts +88 -0
- package/dist/mcp/warm.d.ts.map +1 -0
- package/dist/mcp/warm.js +331 -0
- package/dist/mcp/warm.js.map +1 -0
- package/dist/orchestrator.d.ts +46 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +596 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/policy.d.ts +51 -0
- package/dist/policy.d.ts.map +1 -0
- package/dist/policy.js +201 -0
- package/dist/policy.js.map +1 -0
- package/dist/risk.d.ts +31 -0
- package/dist/risk.d.ts.map +1 -0
- package/dist/risk.js +92 -0
- package/dist/risk.js.map +1 -0
- package/dist/stats.d.ts +72 -0
- package/dist/stats.d.ts.map +1 -0
- package/dist/stats.js +217 -0
- package/dist/stats.js.map +1 -0
- package/dist/telemetry/collector.d.ts +10 -0
- package/dist/telemetry/collector.d.ts.map +1 -0
- package/dist/telemetry/collector.js +75 -0
- package/dist/telemetry/collector.js.map +1 -0
- package/dist/telemetry/consent.d.ts +9 -0
- package/dist/telemetry/consent.d.ts.map +1 -0
- package/dist/telemetry/consent.js +42 -0
- package/dist/telemetry/consent.js.map +1 -0
- package/dist/telemetry/installation.d.ts +2 -0
- package/dist/telemetry/installation.d.ts.map +1 -0
- package/dist/telemetry/installation.js +32 -0
- package/dist/telemetry/installation.js.map +1 -0
- package/dist/telemetry/sanitizer.d.ts +5 -0
- package/dist/telemetry/sanitizer.d.ts.map +1 -0
- package/dist/telemetry/sanitizer.js +60 -0
- package/dist/telemetry/sanitizer.js.map +1 -0
- package/dist/telemetry/types.d.ts +39 -0
- package/dist/telemetry/types.d.ts.map +1 -0
- package/dist/telemetry/types.js +4 -0
- package/dist/telemetry/types.js.map +1 -0
- package/dist/telemetry/uploader.d.ts +12 -0
- package/dist/telemetry/uploader.d.ts.map +1 -0
- package/dist/telemetry/uploader.js +92 -0
- package/dist/telemetry/uploader.js.map +1 -0
- package/dist/util/logger.d.ts +19 -0
- package/dist/util/logger.d.ts.map +1 -0
- package/dist/util/logger.js +58 -0
- package/dist/util/logger.js.map +1 -0
- package/dist/util/safe-paths.d.ts +8 -0
- package/dist/util/safe-paths.d.ts.map +1 -0
- package/dist/util/safe-paths.js +102 -0
- package/dist/util/safe-paths.js.map +1 -0
- package/dist/util/subprocess.d.ts +32 -0
- package/dist/util/subprocess.d.ts.map +1 -0
- package/dist/util/subprocess.js +137 -0
- package/dist/util/subprocess.js.map +1 -0
- package/package.json +93 -0
package/dist/cache.js
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LMDB-backed cache for engine results and other per-project state.
|
|
3
|
+
*
|
|
4
|
+
* Keys are namespaced strings; values are JSON.
|
|
5
|
+
* Falls back to in-memory Map if LMDB fails to load (e.g. native binding
|
|
6
|
+
* missing on a host) — the gate degrades to "no cache" but still works.
|
|
7
|
+
*/
|
|
8
|
+
import { mkdirSync } from "node:fs";
|
|
9
|
+
import { join, resolve } from "node:path";
|
|
10
|
+
import { getLogger } from "./util/logger.js";
|
|
11
|
+
const log = getLogger("aegis.cache");
|
|
12
|
+
class MemoryBackend {
|
|
13
|
+
store = new Map();
|
|
14
|
+
get(key) {
|
|
15
|
+
const e = this.store.get(key);
|
|
16
|
+
if (!e)
|
|
17
|
+
return undefined;
|
|
18
|
+
if (e.exp !== 0 && e.exp < Date.now()) {
|
|
19
|
+
this.store.delete(key);
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return e.v;
|
|
23
|
+
}
|
|
24
|
+
put(key, value, ttlMs) {
|
|
25
|
+
this.store.set(key, { v: value, exp: ttlMs ? Date.now() + ttlMs : 0 });
|
|
26
|
+
}
|
|
27
|
+
delete(key) {
|
|
28
|
+
this.store.delete(key);
|
|
29
|
+
}
|
|
30
|
+
async close() {
|
|
31
|
+
this.store.clear();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
class LmdbBackend {
|
|
35
|
+
db;
|
|
36
|
+
constructor(db) {
|
|
37
|
+
this.db = db;
|
|
38
|
+
}
|
|
39
|
+
get(key) {
|
|
40
|
+
try {
|
|
41
|
+
const raw = this.db.get(key);
|
|
42
|
+
if (!raw)
|
|
43
|
+
return undefined;
|
|
44
|
+
if (raw.exp !== 0 && raw.exp < Date.now()) {
|
|
45
|
+
void this.db.remove(key);
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
return raw.v;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
log.debug("lmdb get failed", { key, err: String(err) });
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async put(key, value, ttlMs) {
|
|
56
|
+
try {
|
|
57
|
+
// AWAIT the underlying promise. lmdb-js batches writes; without await,
|
|
58
|
+
// a subsequent get from the same process may not see the value in time
|
|
59
|
+
// (manifests as ``undefined`` reads immediately after writes).
|
|
60
|
+
await this.db.put(key, { v: value, exp: ttlMs ? Date.now() + ttlMs : 0 });
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
log.debug("lmdb put failed", { key, err: String(err) });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async delete(key) {
|
|
67
|
+
try {
|
|
68
|
+
await this.db.remove(key);
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
log.debug("lmdb remove failed", { key, err: String(err) });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async close() {
|
|
75
|
+
try {
|
|
76
|
+
await this.db.close();
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// best-effort
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let _backend = null;
|
|
84
|
+
let _initAttempted = false;
|
|
85
|
+
async function getBackend(_projectRoot) {
|
|
86
|
+
if (_backend)
|
|
87
|
+
return _backend;
|
|
88
|
+
if (_initAttempted) {
|
|
89
|
+
_backend = new MemoryBackend();
|
|
90
|
+
return _backend;
|
|
91
|
+
}
|
|
92
|
+
_initAttempted = true;
|
|
93
|
+
// Use a SINGLE cache shared by all projects (keys are project-hashed via
|
|
94
|
+
// rootKey() upstream), located under the user's home dir or
|
|
95
|
+
// ``AEGIS_HOME``. Per-cwd caches led to misses when ``aegis index`` and
|
|
96
|
+
// ``aegis scan`` were invoked from different working directories.
|
|
97
|
+
try {
|
|
98
|
+
const lmdbMod = (await import("lmdb"));
|
|
99
|
+
const home = process.env.AEGIS_HOME ?? resolve(process.env.HOME ?? process.env.USERPROFILE ?? ".", ".aegis");
|
|
100
|
+
const dir = resolve(home, "cache");
|
|
101
|
+
mkdirSync(dir, { recursive: true });
|
|
102
|
+
const db = lmdbMod.open({
|
|
103
|
+
path: join(dir, "aegis-cache.mdb"),
|
|
104
|
+
compression: true,
|
|
105
|
+
});
|
|
106
|
+
_backend = new LmdbBackend(db);
|
|
107
|
+
log.info("cache backend: lmdb (shared)", { path: dir });
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
log.warn("lmdb unavailable; falling back to in-memory cache", { err: String(err) });
|
|
111
|
+
_backend = new MemoryBackend();
|
|
112
|
+
}
|
|
113
|
+
return _backend;
|
|
114
|
+
}
|
|
115
|
+
export class Cache {
|
|
116
|
+
projectRoot;
|
|
117
|
+
constructor(projectRoot) {
|
|
118
|
+
this.projectRoot = projectRoot;
|
|
119
|
+
}
|
|
120
|
+
async get(key) {
|
|
121
|
+
const b = await getBackend(this.projectRoot);
|
|
122
|
+
return b.get(key);
|
|
123
|
+
}
|
|
124
|
+
async put(key, value, ttlMs) {
|
|
125
|
+
const b = await getBackend(this.projectRoot);
|
|
126
|
+
await b.put(key, value, ttlMs);
|
|
127
|
+
}
|
|
128
|
+
async delete(key) {
|
|
129
|
+
const b = await getBackend(this.projectRoot);
|
|
130
|
+
await b.delete(key);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Cache key for an engine result on a specific (engine, lang, content_hash). */
|
|
134
|
+
import { createHash } from "node:crypto";
|
|
135
|
+
export function cacheKeyForEngine(engine, lang, content) {
|
|
136
|
+
const h = createHash("sha256")
|
|
137
|
+
.update(engine)
|
|
138
|
+
.update("\0")
|
|
139
|
+
.update(lang)
|
|
140
|
+
.update("\0")
|
|
141
|
+
.update(content)
|
|
142
|
+
.digest("hex")
|
|
143
|
+
.slice(0, 32);
|
|
144
|
+
return `eng:${engine}:${lang}:${h}`;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../src/cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI / LLM-specific dangerous-sinks scanner — multi-language (Python + JS/TS).
|
|
3
|
+
*
|
|
4
|
+
* Targets the prompt-injection and LLM-misuse patterns from OWASP Top 10 for
|
|
5
|
+
* LLM Applications 2025 + the corpus of real-world LLM-app CVEs. These have
|
|
6
|
+
* no signal in classical SAST and Vul-RAG misses them too because the KB is
|
|
7
|
+
* pre-LLM-era.
|
|
8
|
+
*
|
|
9
|
+
* AI-01 Direct prompt injection: untrusted text concatenated into prompt
|
|
10
|
+
* without delimiters / tag-marking (CWE-1427)
|
|
11
|
+
* AI-02 System-role contamination: f"...{user_input}..." used as the
|
|
12
|
+
* system message (CWE-1427)
|
|
13
|
+
* AI-03 Indirect prompt injection: tool output / web-search result fed
|
|
14
|
+
* back into the next prompt without quoting (CWE-1426)
|
|
15
|
+
* AI-04 Hardcoded LLM API key: sk-..., claude-..., AIza... literal in source
|
|
16
|
+
* (CWE-798) — broader catch than the generic secret-scan
|
|
17
|
+
* AI-05 Missing rate limit on chat.completions in a route handler (CWE-770)
|
|
18
|
+
* AI-06 Template-based prompt builder where the SOURCE template comes from
|
|
19
|
+
* user input (CWE-1427)
|
|
20
|
+
*
|
|
21
|
+
* All patterns are language-aware: Python ones use Python idioms (f-string,
|
|
22
|
+
* messages=[{...}], anthropic.messages.create); JS ones use template
|
|
23
|
+
* literals + openai.chat.completions.create.
|
|
24
|
+
*/
|
|
25
|
+
import { Engine, EngineRunInput, EngineRunResult } from "./types.js";
|
|
26
|
+
import { Lang } from "../lang.js";
|
|
27
|
+
interface SinkRule {
|
|
28
|
+
id: string;
|
|
29
|
+
cwe: string;
|
|
30
|
+
severity: "high" | "critical";
|
|
31
|
+
what: string;
|
|
32
|
+
pattern: RegExp;
|
|
33
|
+
isDangerous: (firstArg: string, allArgs: string, fullContent?: string) => boolean;
|
|
34
|
+
fileGate?: (fullContent: string) => boolean;
|
|
35
|
+
remediation: string;
|
|
36
|
+
langs: ReadonlyArray<Lang>;
|
|
37
|
+
}
|
|
38
|
+
declare function isLlmFile(c: string): boolean;
|
|
39
|
+
declare function tainted(s: string): boolean;
|
|
40
|
+
export declare class AiSinksEngine implements Engine {
|
|
41
|
+
readonly name: "ai-sinks";
|
|
42
|
+
readonly languages: ReadonlyArray<Lang>;
|
|
43
|
+
available(): Promise<boolean>;
|
|
44
|
+
run(input: EngineRunInput): Promise<EngineRunResult>;
|
|
45
|
+
}
|
|
46
|
+
export declare const _testing: {
|
|
47
|
+
RULES: readonly SinkRule[];
|
|
48
|
+
isLlmFile: typeof isLlmFile;
|
|
49
|
+
tainted: typeof tainted;
|
|
50
|
+
};
|
|
51
|
+
export {};
|
|
52
|
+
//# sourceMappingURL=ai-sinks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sinks.d.ts","sourceRoot":"","sources":["../../src/engines/ai-sinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAGlC,UAAU,QAAQ;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,GAAG,UAAU,CAAC;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;IAClF,QAAQ,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC;CAC5B;AAGD,iBAAS,SAAS,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAIrC;AAOD,iBAAS,OAAO,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEnC;AA4ID,qBAAa,aAAc,YAAW,MAAM;IAC1C,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IACpC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,IAAI,CAAC,CAA0C;IAE3E,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAI7B,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CA6D3D;AAED,eAAO,MAAM,QAAQ;;;;CAAgC,CAAC"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { makeFindingId } from "../findings.js";
|
|
2
|
+
import { isLineSuppressed, isTestOrFixturePath } from "./pragma.js";
|
|
3
|
+
// Files that look like they wire an LLM call.
|
|
4
|
+
function isLlmFile(c) {
|
|
5
|
+
return /\b(?:openai|anthropic|google\.generativeai|cohere|together|groq|ollama|@anthropic-ai\/sdk|claude(?:-3|-4|_sdk))\b/i.test(c);
|
|
6
|
+
}
|
|
7
|
+
// Common taint sources across both languages — anything that smells like
|
|
8
|
+
// untrusted user / network input.
|
|
9
|
+
const TAINT_SOURCE_RE = /\b(?:request\.(?:args|form|json|values|cookies|files|data)\b|req\.(?:body|params|query|cookies)\b|input\s*\(\s*\)|sys\.argv\b|process\.argv\b|process\.env\b(?!\.NODE_ENV\b)|tool_result\b|search_result\b|scraped_content\b|raw_email\b|webhook_body\b)/;
|
|
10
|
+
function tainted(s) {
|
|
11
|
+
return TAINT_SOURCE_RE.test(s);
|
|
12
|
+
}
|
|
13
|
+
/** Check if an f-string capture (e.g. just the variable name "q") is
|
|
14
|
+
* tainted — directly OR via assignment somewhere else in the file.
|
|
15
|
+
*
|
|
16
|
+
* prompt = f"... {q}" <- capture is "q"
|
|
17
|
+
* q = request.args.get('q','') <- assignment elsewhere
|
|
18
|
+
*
|
|
19
|
+
* We escape the capture as a regex literal and look for
|
|
20
|
+
* <name> = <anything-with-a-taint-source>
|
|
21
|
+
* Returns true on direct match OR transitive assignment. */
|
|
22
|
+
function captureIsTainted(capture, fullContent) {
|
|
23
|
+
if (TAINT_SOURCE_RE.test(capture))
|
|
24
|
+
return true;
|
|
25
|
+
if (!fullContent)
|
|
26
|
+
return false;
|
|
27
|
+
const name = capture.trim().split(/[\s,.\[]/, 1)[0];
|
|
28
|
+
if (!name || name.length === 0 || /\W/.test(name))
|
|
29
|
+
return false;
|
|
30
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
31
|
+
// Match: <name> = <expression involving a taint source>
|
|
32
|
+
// (the expression can span the rest of the line)
|
|
33
|
+
const assignRe = new RegExp(`\\b${escaped}\\s*=\\s*[^=\\n]*?(?:${TAINT_SOURCE_RE.source})`);
|
|
34
|
+
return assignRe.test(fullContent);
|
|
35
|
+
}
|
|
36
|
+
const RULES = [
|
|
37
|
+
{
|
|
38
|
+
id: "prompt-injection-fstring",
|
|
39
|
+
cwe: "CWE-1427",
|
|
40
|
+
severity: "high",
|
|
41
|
+
what: "Python f-string prompt with untrusted interpolation — direct prompt injection (attacker steers the model)",
|
|
42
|
+
// Looks for: prompt = f"...{tainted}..." OR content = f"...{request.x}..."
|
|
43
|
+
// Direct assignment OR dict-value form. Simpler than the previous
|
|
44
|
+
// monster regex — matches: `prompt = f"...{x}..."` and
|
|
45
|
+
// `{"content": f"...{x}..."}`.
|
|
46
|
+
pattern: /(?:\b(?:prompt|message|content|system|user_message|system_prompt|systemPrompt)\s*=\s*|['"]content['"]\s*:\s*)[rR]?[fF]['"][^'"]*\{([^{}]+)\}/g,
|
|
47
|
+
isDangerous: (capture, _all, content) => captureIsTainted(capture, content),
|
|
48
|
+
fileGate: (c) => isLlmFile(c),
|
|
49
|
+
remediation: "Wrap untrusted text in clearly marked delimiters and instruct the model in the SYSTEM prompt " +
|
|
50
|
+
"that anything inside the delimiter is data, never instructions:\n" +
|
|
51
|
+
" user_msg = f'Answer the user. Their message is delimited by <user_input>...</user_input>.'\n" +
|
|
52
|
+
" user_msg += f'\\n<user_input>{untrusted}</user_input>'\n" +
|
|
53
|
+
"Plus: refuse-on-instruction-conflict + tag-only-mode in tool schemas.",
|
|
54
|
+
langs: ["python"],
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
id: "prompt-injection-template-literal",
|
|
58
|
+
cwe: "CWE-1427",
|
|
59
|
+
severity: "high",
|
|
60
|
+
what: "JS template-literal prompt with untrusted interpolation — direct prompt injection",
|
|
61
|
+
pattern: /(?:\b(?:prompt|message|content|system|userMessage|systemPrompt)\s*=\s*|['"]content['"]\s*:\s*)`[^`]*\$\{([^{}]+)\}/g,
|
|
62
|
+
isDangerous: (capture, _all, content) => captureIsTainted(capture, content),
|
|
63
|
+
fileGate: (c) => isLlmFile(c),
|
|
64
|
+
remediation: "Wrap untrusted text in clearly marked delimiters in the user message and instruct the SYSTEM " +
|
|
65
|
+
"prompt that delimited content is data:\n" +
|
|
66
|
+
" const userMsg = `User input is in <user_input> tags.\\n<user_input>${untrusted}</user_input>`;\n" +
|
|
67
|
+
"Plus: structured output (JSON schema) + refuse-on-instruction-conflict.",
|
|
68
|
+
langs: ["javascript", "typescript"],
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
id: "llm-tool-result-fed-back-raw",
|
|
72
|
+
cwe: "CWE-1426",
|
|
73
|
+
severity: "high",
|
|
74
|
+
what: "Raw tool/search/scrape output appended back to the prompt without delimiters — indirect prompt injection",
|
|
75
|
+
// Patterns like: messages.append({"role":"user","content": tool_result})
|
|
76
|
+
// OR prompt += search_result OR messages.push({content: scraped})
|
|
77
|
+
pattern: /(?:messages\.(?:append|push)\s*\(|(?:prompt|message|context)\s*[+]?=)[^;\n]*\b(tool_result|search_result|scraped_content|webhook_body|raw_email|tool_output)\b/g,
|
|
78
|
+
isDangerous: () => true,
|
|
79
|
+
fileGate: (c) => isLlmFile(c),
|
|
80
|
+
remediation: "Treat ALL tool / network / web-scraped output as untrusted. Wrap it: " +
|
|
81
|
+
"f'<tool_output>{result}</tool_output>' AND set a system instruction that anything inside such " +
|
|
82
|
+
"tags is data. Better: have the tool return STRUCTURED output (JSON), parse it server-side, and " +
|
|
83
|
+
"expose only the fields you need to the next prompt.",
|
|
84
|
+
langs: ["python", "javascript", "typescript"],
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: "llm-hardcoded-api-key",
|
|
88
|
+
cwe: "CWE-798",
|
|
89
|
+
severity: "critical",
|
|
90
|
+
what: "Hardcoded LLM provider API key in source",
|
|
91
|
+
// Match common prefixes for OpenAI / Anthropic / Google / Cohere / Mistral.
|
|
92
|
+
pattern: /['"`](sk-(?:proj-|ant-|live-)?[A-Za-z0-9_-]{20,}|claude-[A-Za-z0-9_-]{20,}|AIza[A-Za-z0-9_-]{30,}|co\.[A-Za-z0-9]{20,}|mst-[A-Za-z0-9]{20,})['"`]/g,
|
|
93
|
+
isDangerous: (capture) => {
|
|
94
|
+
// Exclude obvious template placeholders.
|
|
95
|
+
const v = capture.replace(/['"`]/g, "");
|
|
96
|
+
if (/EXAMPLE|YOUR[_-]?KEY|PLACEHOLDER|xxxx|\.\.\.|<.*>/i.test(v))
|
|
97
|
+
return false;
|
|
98
|
+
return true;
|
|
99
|
+
},
|
|
100
|
+
remediation: "Load from env: api_key=os.environ['ANTHROPIC_API_KEY']. Hardcoded LLM keys end up in git history " +
|
|
101
|
+
"and on PyPI / npm / GitHub — automated scanners harvest them within minutes and bill them out. " +
|
|
102
|
+
"Rotate the exposed key NOW at the provider console.",
|
|
103
|
+
langs: ["python", "javascript", "typescript"],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
id: "llm-system-prompt-interpolates-user",
|
|
107
|
+
cwe: "CWE-1427",
|
|
108
|
+
severity: "high",
|
|
109
|
+
what: "System prompt contains f-string / template interpolation of untrusted input — attacker can rewrite role",
|
|
110
|
+
// Match: system_prompt = f"...{tainted}..." OR system_prompt = `...${tainted}...`
|
|
111
|
+
pattern: /\b(?:system_prompt|systemPrompt|SYSTEM_PROMPT)\s*=\s*(?:[rR]?[fF]['"][^'"]*\{([^{}]+)\}|`[^`]*\$\{([^{}]+)\})/g,
|
|
112
|
+
isDangerous: (_first, all, content) => TAINT_SOURCE_RE.test(all) || captureIsTainted(all, content),
|
|
113
|
+
fileGate: (c) => isLlmFile(c),
|
|
114
|
+
remediation: "Keep the system prompt 100% STATIC. Move all user-controlled values to the user-role message " +
|
|
115
|
+
"with explicit delimiters. A system prompt that interpolates user input gives the attacker the " +
|
|
116
|
+
"ability to insert role-overriding instructions that the model is trained to obey.",
|
|
117
|
+
langs: ["python", "javascript", "typescript"],
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
id: "llm-jinja-from-string-render",
|
|
121
|
+
cwe: "CWE-1427",
|
|
122
|
+
severity: "critical",
|
|
123
|
+
what: "Jinja Template / from_string(user_input).render(...) used to build an LLM prompt — template-injection-via-LLM",
|
|
124
|
+
// Any .from_string(...) call counts when we're in an LLM file.
|
|
125
|
+
pattern: /\.from_string\s*\(([^()]*(?:\([^()]*\)[^()]*)*)\)/g,
|
|
126
|
+
isDangerous: (first) => TAINT_SOURCE_RE.test(first),
|
|
127
|
+
fileGate: (c) => isLlmFile(c),
|
|
128
|
+
remediation: "Never build a prompt via runtime template-source from user input. Use parameter substitution " +
|
|
129
|
+
"into a static template (Jinja2.Template(STATIC).render(user=untrusted)). The render itself is safe; " +
|
|
130
|
+
"the SOURCE-as-data is the bug.",
|
|
131
|
+
langs: ["python"],
|
|
132
|
+
},
|
|
133
|
+
];
|
|
134
|
+
export class AiSinksEngine {
|
|
135
|
+
name = "ai-sinks";
|
|
136
|
+
languages = ["python", "javascript", "typescript"];
|
|
137
|
+
async available() {
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
async run(input) {
|
|
141
|
+
const t0 = Date.now();
|
|
142
|
+
const findings = [];
|
|
143
|
+
if (input.lang !== "python" &&
|
|
144
|
+
input.lang !== "javascript" &&
|
|
145
|
+
input.lang !== "typescript") {
|
|
146
|
+
return { engine: this.name, findings: [], unavailable: false, durationMs: 0 };
|
|
147
|
+
}
|
|
148
|
+
if (isTestOrFixturePath(input.filePath)) {
|
|
149
|
+
return { engine: this.name, findings: [], unavailable: false, durationMs: 0 };
|
|
150
|
+
}
|
|
151
|
+
const content = input.content;
|
|
152
|
+
const lines = content.split(/\r?\n/);
|
|
153
|
+
const seen = new Set();
|
|
154
|
+
for (const rule of RULES) {
|
|
155
|
+
if (!rule.langs.includes(input.lang))
|
|
156
|
+
continue;
|
|
157
|
+
if (rule.fileGate && !rule.fileGate(content))
|
|
158
|
+
continue;
|
|
159
|
+
rule.pattern.lastIndex = 0;
|
|
160
|
+
let m;
|
|
161
|
+
while ((m = rule.pattern.exec(content)) !== null) {
|
|
162
|
+
const allArgs = m[1] ?? "";
|
|
163
|
+
if (!rule.isDangerous(allArgs, allArgs, content))
|
|
164
|
+
continue;
|
|
165
|
+
const upTo = content.slice(0, m.index);
|
|
166
|
+
const line = upTo.split(/\r?\n/).length;
|
|
167
|
+
const snippet = (lines[line - 1] ?? "").slice(0, 400);
|
|
168
|
+
if (isLineSuppressed(snippet, rule.id))
|
|
169
|
+
continue;
|
|
170
|
+
const id = makeFindingId({
|
|
171
|
+
engine: this.name,
|
|
172
|
+
file: input.filePath,
|
|
173
|
+
line,
|
|
174
|
+
rule_id: rule.id,
|
|
175
|
+
});
|
|
176
|
+
if (seen.has(id))
|
|
177
|
+
continue;
|
|
178
|
+
seen.add(id);
|
|
179
|
+
findings.push({
|
|
180
|
+
id,
|
|
181
|
+
engine: "ai-sinks",
|
|
182
|
+
file: input.filePath,
|
|
183
|
+
line,
|
|
184
|
+
rule_id: rule.id,
|
|
185
|
+
cwe: rule.cwe,
|
|
186
|
+
severity: rule.severity,
|
|
187
|
+
message: `${rule.what}. Likely ${rule.cwe} — review and remediate before merging.`,
|
|
188
|
+
evidence: { snippet },
|
|
189
|
+
confidence: 0.75,
|
|
190
|
+
source: "pattern",
|
|
191
|
+
remediation: rule.remediation,
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
engine: this.name,
|
|
197
|
+
findings,
|
|
198
|
+
unavailable: false,
|
|
199
|
+
durationMs: Date.now() - t0,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
export const _testing = { RULES, isLlmFile, tainted };
|
|
204
|
+
//# sourceMappingURL=ai-sinks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-sinks.js","sourceRoot":"","sources":["../../src/engines/ai-sinks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Engine, EngineRunInput, EngineRunResult } from "./types.js";
|
|
2
|
+
import { Lang } from "../lang.js";
|
|
3
|
+
export declare class ESLintEngine implements Engine {
|
|
4
|
+
readonly name = "eslint";
|
|
5
|
+
readonly languages: readonly Lang[];
|
|
6
|
+
available(): Promise<boolean>;
|
|
7
|
+
run(input: EngineRunInput): Promise<EngineRunResult>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=eslint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint.d.ts","sourceRoot":"","sources":["../../src/engines/eslint.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAErE,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AA2JlC,qBAAa,YAAa,YAAW,MAAM;IACzC,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,SAAS,kBAAa;IAEzB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAK7B,GAAG,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAwG3D"}
|