@ai-dossier/core 1.2.0 → 1.3.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.
- package/dist/coherence/checks.d.ts +13 -0
- package/dist/coherence/checks.d.ts.map +1 -0
- package/dist/coherence/checks.js +239 -0
- package/dist/coherence/checks.js.map +1 -0
- package/dist/coherence/index.d.ts +47 -0
- package/dist/coherence/index.d.ts.map +1 -0
- package/dist/coherence/index.js +89 -0
- package/dist/coherence/index.js.map +1 -0
- package/dist/coherence/types.d.ts +70 -0
- package/dist/coherence/types.d.ts.map +1 -0
- package/dist/coherence/types.js +11 -0
- package/dist/coherence/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -1
- package/dist/index.js.map +1 -1
- package/dist/security-scanner/code-block-context.d.ts +24 -0
- package/dist/security-scanner/code-block-context.d.ts.map +1 -0
- package/dist/security-scanner/code-block-context.js +68 -0
- package/dist/security-scanner/code-block-context.js.map +1 -0
- package/dist/security-scanner/index.d.ts +21 -0
- package/dist/security-scanner/index.d.ts.map +1 -0
- package/dist/security-scanner/index.js +92 -0
- package/dist/security-scanner/index.js.map +1 -0
- package/dist/security-scanner/match-utils.d.ts +21 -0
- package/dist/security-scanner/match-utils.d.ts.map +1 -0
- package/dist/security-scanner/match-utils.js +40 -0
- package/dist/security-scanner/match-utils.js.map +1 -0
- package/dist/security-scanner/registry.d.ts +11 -0
- package/dist/security-scanner/registry.d.ts.map +1 -0
- package/dist/security-scanner/registry.js +79 -0
- package/dist/security-scanner/registry.js.map +1 -0
- package/dist/security-scanner/rules/agent-hijacking.d.ts +3 -0
- package/dist/security-scanner/rules/agent-hijacking.d.ts.map +1 -0
- package/dist/security-scanner/rules/agent-hijacking.js +56 -0
- package/dist/security-scanner/rules/agent-hijacking.js.map +1 -0
- package/dist/security-scanner/rules/dangerous-execution.d.ts +3 -0
- package/dist/security-scanner/rules/dangerous-execution.d.ts.map +1 -0
- package/dist/security-scanner/rules/dangerous-execution.js +86 -0
- package/dist/security-scanner/rules/dangerous-execution.js.map +1 -0
- package/dist/security-scanner/rules/data-exfiltration.d.ts +3 -0
- package/dist/security-scanner/rules/data-exfiltration.d.ts.map +1 -0
- package/dist/security-scanner/rules/data-exfiltration.js +61 -0
- package/dist/security-scanner/rules/data-exfiltration.js.map +1 -0
- package/dist/security-scanner/rules/index.d.ts +12 -0
- package/dist/security-scanner/rules/index.d.ts.map +1 -0
- package/dist/security-scanner/rules/index.js +30 -0
- package/dist/security-scanner/rules/index.js.map +1 -0
- package/dist/security-scanner/rules/prompt-injection.d.ts +3 -0
- package/dist/security-scanner/rules/prompt-injection.d.ts.map +1 -0
- package/dist/security-scanner/rules/prompt-injection.js +56 -0
- package/dist/security-scanner/rules/prompt-injection.js.map +1 -0
- package/dist/security-scanner/rules/supply-chain.d.ts +3 -0
- package/dist/security-scanner/rules/supply-chain.d.ts.map +1 -0
- package/dist/security-scanner/rules/supply-chain.js +61 -0
- package/dist/security-scanner/rules/supply-chain.js.map +1 -0
- package/dist/security-scanner/rules/unicode-attacks.d.ts +3 -0
- package/dist/security-scanner/rules/unicode-attacks.d.ts.map +1 -0
- package/dist/security-scanner/rules/unicode-attacks.js +83 -0
- package/dist/security-scanner/rules/unicode-attacks.js.map +1 -0
- package/dist/security-scanner/rules/url-threats.d.ts +3 -0
- package/dist/security-scanner/rules/url-threats.d.ts.map +1 -0
- package/dist/security-scanner/rules/url-threats.js +82 -0
- package/dist/security-scanner/rules/url-threats.js.map +1 -0
- package/dist/security-scanner/rules/xss-html-injection.d.ts +3 -0
- package/dist/security-scanner/rules/xss-html-injection.d.ts.map +1 -0
- package/dist/security-scanner/rules/xss-html-injection.js +82 -0
- package/dist/security-scanner/rules/xss-html-injection.js.map +1 -0
- package/dist/security-scanner/types.d.ts +45 -0
- package/dist/security-scanner/types.d.ts.map +1 -0
- package/dist/security-scanner/types.js +3 -0
- package/dist/security-scanner/types.js.map +1 -0
- package/dist/trace-recorder.d.ts +45 -0
- package/dist/trace-recorder.d.ts.map +1 -0
- package/dist/trace-recorder.js +43 -0
- package/dist/trace-recorder.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defaultSecurityRules = exports.xssHtmlInjectionRule = exports.urlThreatsRule = exports.unicodeAttacksRule = exports.supplyChainRule = exports.promptInjectionRule = exports.dataExfiltrationRule = exports.dangerousExecutionRule = exports.agentHijackingRule = void 0;
|
|
4
|
+
const agent_hijacking_1 = require("./agent-hijacking");
|
|
5
|
+
Object.defineProperty(exports, "agentHijackingRule", { enumerable: true, get: function () { return agent_hijacking_1.agentHijackingRule; } });
|
|
6
|
+
const dangerous_execution_1 = require("./dangerous-execution");
|
|
7
|
+
Object.defineProperty(exports, "dangerousExecutionRule", { enumerable: true, get: function () { return dangerous_execution_1.dangerousExecutionRule; } });
|
|
8
|
+
const data_exfiltration_1 = require("./data-exfiltration");
|
|
9
|
+
Object.defineProperty(exports, "dataExfiltrationRule", { enumerable: true, get: function () { return data_exfiltration_1.dataExfiltrationRule; } });
|
|
10
|
+
const prompt_injection_1 = require("./prompt-injection");
|
|
11
|
+
Object.defineProperty(exports, "promptInjectionRule", { enumerable: true, get: function () { return prompt_injection_1.promptInjectionRule; } });
|
|
12
|
+
const supply_chain_1 = require("./supply-chain");
|
|
13
|
+
Object.defineProperty(exports, "supplyChainRule", { enumerable: true, get: function () { return supply_chain_1.supplyChainRule; } });
|
|
14
|
+
const unicode_attacks_1 = require("./unicode-attacks");
|
|
15
|
+
Object.defineProperty(exports, "unicodeAttacksRule", { enumerable: true, get: function () { return unicode_attacks_1.unicodeAttacksRule; } });
|
|
16
|
+
const url_threats_1 = require("./url-threats");
|
|
17
|
+
Object.defineProperty(exports, "urlThreatsRule", { enumerable: true, get: function () { return url_threats_1.urlThreatsRule; } });
|
|
18
|
+
const xss_html_injection_1 = require("./xss-html-injection");
|
|
19
|
+
Object.defineProperty(exports, "xssHtmlInjectionRule", { enumerable: true, get: function () { return xss_html_injection_1.xssHtmlInjectionRule; } });
|
|
20
|
+
exports.defaultSecurityRules = [
|
|
21
|
+
prompt_injection_1.promptInjectionRule,
|
|
22
|
+
agent_hijacking_1.agentHijackingRule,
|
|
23
|
+
dangerous_execution_1.dangerousExecutionRule,
|
|
24
|
+
unicode_attacks_1.unicodeAttacksRule,
|
|
25
|
+
data_exfiltration_1.dataExfiltrationRule,
|
|
26
|
+
xss_html_injection_1.xssHtmlInjectionRule,
|
|
27
|
+
url_threats_1.urlThreatsRule,
|
|
28
|
+
supply_chain_1.supplyChainRule,
|
|
29
|
+
];
|
|
30
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/security-scanner/rules/index.ts"],"names":[],"mappings":";;;AACA,uDAAuD;AAUrD,mGAVO,oCAAkB,OAUP;AATpB,+DAA+D;AAU7D,uGAVO,4CAAsB,OAUP;AATxB,2DAA2D;AAUzD,qGAVO,wCAAoB,OAUP;AATtB,yDAAyD;AAUvD,oGAVO,sCAAmB,OAUP;AATrB,iDAAiD;AAU/C,gGAVO,8BAAe,OAUP;AATjB,uDAAuD;AAUrD,mGAVO,oCAAkB,OAUP;AATpB,+CAA+C;AAU7C,+FAVO,4BAAc,OAUP;AAThB,6DAA4D;AAU1D,qGAVO,yCAAoB,OAUP;AAGT,QAAA,oBAAoB,GAAmB;IAClD,sCAAmB;IACnB,oCAAkB;IAClB,4CAAsB;IACtB,oCAAkB;IAClB,wCAAoB;IACpB,yCAAoB;IACpB,4BAAc;IACd,8BAAe;CAChB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-injection.d.ts","sourceRoot":"","sources":["../../../src/security-scanner/rules/prompt-injection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,YAAY,EAAE,MAAM,UAAU,CAAC;AA0C9D,eAAO,MAAM,mBAAmB,EAAE,YA0BjC,CAAC"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.promptInjectionRule = void 0;
|
|
4
|
+
const code_block_context_1 = require("../code-block-context");
|
|
5
|
+
const match_utils_1 = require("../match-utils");
|
|
6
|
+
/**
|
|
7
|
+
* Patterns that indicate prompt injection — attempts to insert hidden instructions
|
|
8
|
+
* that an LLM would interpret as system/user directives.
|
|
9
|
+
*/
|
|
10
|
+
const PROMPT_INJECTION_PATTERNS = [
|
|
11
|
+
// HTML comment directives
|
|
12
|
+
{
|
|
13
|
+
pattern: /<!--\s*(system|instruction|ignore|override|forget|disregard|new\s+task)[\s\S]*?-->/gi,
|
|
14
|
+
description: 'HTML comment containing directive keywords',
|
|
15
|
+
},
|
|
16
|
+
// Explicit system prompt injection markers
|
|
17
|
+
{
|
|
18
|
+
pattern: /\[SYSTEM\]|\[INST\]|\[\/INST\]|<\|im_start\|>|<\|im_end\|>/gi,
|
|
19
|
+
description: 'LLM chat template markers (system/inst delimiters)',
|
|
20
|
+
},
|
|
21
|
+
// Attempts to redefine the assistant identity
|
|
22
|
+
{
|
|
23
|
+
pattern: /you\s+are\s+(?:now|a\s+new|no\s+longer)\b|from\s+now\s+on,?\s+(?:you|ignore|forget)/gi,
|
|
24
|
+
description: 'Identity override attempt',
|
|
25
|
+
},
|
|
26
|
+
// "Ignore previous" family
|
|
27
|
+
{
|
|
28
|
+
pattern: /(?:ignore|disregard|forget|override)\s+(?:all\s+)?(?:previous|above|prior|earlier)\s+(?:instructions?|rules?|context|prompts?|constraints?)/gi,
|
|
29
|
+
description: 'Instruction override attempt ("ignore previous...")',
|
|
30
|
+
},
|
|
31
|
+
// Hidden text via HTML attributes
|
|
32
|
+
{
|
|
33
|
+
pattern: /<\w+[^>]*\bstyle\s*=\s*["'][^"']*(?:display\s*:\s*none|visibility\s*:\s*hidden|font-size\s*:\s*0|opacity\s*:\s*0|color\s*:\s*(?:white|transparent|#fff(?:fff)?))[^"']*["'][^>]*>/gi,
|
|
34
|
+
description: 'HTML element with hidden/invisible styling',
|
|
35
|
+
},
|
|
36
|
+
// Base64-encoded payloads that look like embedded instructions
|
|
37
|
+
{
|
|
38
|
+
pattern: /<!--[\s\S]*?(?:[A-Za-z0-9+/]{40,}={0,2})[\s\S]*?-->/g,
|
|
39
|
+
description: 'HTML comment containing base64-encoded payload',
|
|
40
|
+
},
|
|
41
|
+
];
|
|
42
|
+
exports.promptInjectionRule = {
|
|
43
|
+
id: 'prompt-injection',
|
|
44
|
+
category: 'prompt-injection',
|
|
45
|
+
description: 'Detects prompt injection patterns — hidden instructions and system prompt overrides',
|
|
46
|
+
defaultSeverity: 'critical',
|
|
47
|
+
detect(context) {
|
|
48
|
+
const findings = [];
|
|
49
|
+
const codeBlockRanges = (0, code_block_context_1.parseCodeBlockRanges)(context.body);
|
|
50
|
+
for (const { pattern, description } of PROMPT_INJECTION_PATTERNS) {
|
|
51
|
+
findings.push(...(0, match_utils_1.matchPattern)(context.body, pattern, codeBlockRanges, 'prompt-injection', 'prompt-injection', description, 'critical'));
|
|
52
|
+
}
|
|
53
|
+
return findings;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
//# sourceMappingURL=prompt-injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-injection.js","sourceRoot":"","sources":["../../../src/security-scanner/rules/prompt-injection.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAC7D,gDAA8C;AAG9C;;;GAGG;AACH,MAAM,yBAAyB,GAA+C;IAC5E,0BAA0B;IAC1B;QACE,OAAO,EAAE,sFAAsF;QAC/F,WAAW,EAAE,4CAA4C;KAC1D;IACD,2CAA2C;IAC3C;QACE,OAAO,EAAE,8DAA8D;QACvE,WAAW,EAAE,oDAAoD;KAClE;IACD,8CAA8C;IAC9C;QACE,OAAO,EACL,uFAAuF;QACzF,WAAW,EAAE,2BAA2B;KACzC;IACD,2BAA2B;IAC3B;QACE,OAAO,EACL,+IAA+I;QACjJ,WAAW,EAAE,qDAAqD;KACnE;IACD,kCAAkC;IAClC;QACE,OAAO,EACL,oLAAoL;QACtL,WAAW,EAAE,4CAA4C;KAC1D;IACD,+DAA+D;IAC/D;QACE,OAAO,EAAE,sDAAsD;QAC/D,WAAW,EAAE,gDAAgD;KAC9D;CACF,CAAC;AAEW,QAAA,mBAAmB,GAAiB;IAC/C,EAAE,EAAE,kBAAkB;IACtB,QAAQ,EAAE,kBAAkB;IAC5B,WAAW,EACT,qFAAqF;IACvF,eAAe,EAAE,UAAU;IAC3B,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,MAAM,eAAe,GAAG,IAAA,yCAAoB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE3D,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,yBAAyB,EAAE,CAAC;YACjE,QAAQ,CAAC,IAAI,CACX,GAAG,IAAA,0BAAY,EACb,OAAO,CAAC,IAAI,EACZ,OAAO,EACP,eAAe,EACf,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,UAAU,CACX,CACF,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supply-chain.d.ts","sourceRoot":"","sources":["../../../src/security-scanner/rules/supply-chain.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,YAAY,EAAE,MAAM,UAAU,CAAC;AAkD9D,eAAO,MAAM,eAAe,EAAE,YA0B7B,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.supplyChainRule = void 0;
|
|
4
|
+
const code_block_context_1 = require("../code-block-context");
|
|
5
|
+
const match_utils_1 = require("../match-utils");
|
|
6
|
+
/**
|
|
7
|
+
* Patterns for supply chain attacks — fake prerequisites, hook exploitation,
|
|
8
|
+
* package confusion, and CSV injection.
|
|
9
|
+
*/
|
|
10
|
+
const SUPPLY_CHAIN_PATTERNS = [
|
|
11
|
+
// Installing packages from suspicious or unqualified sources
|
|
12
|
+
{
|
|
13
|
+
pattern: /(?:npm\s+install|pip\s+install|gem\s+install|go\s+get|cargo\s+install)\s+.*(?:--registry|--index-url|--extra-index-url|--trusted-host)\s+https?:\/\//g,
|
|
14
|
+
description: 'Package installation from custom/untrusted registry',
|
|
15
|
+
},
|
|
16
|
+
// Git hooks injection (pre-commit, post-checkout, etc.)
|
|
17
|
+
{
|
|
18
|
+
pattern: /\.git\/hooks\/(?:pre-commit|post-commit|pre-push|post-checkout|pre-receive|post-receive|prepare-commit-msg)/g,
|
|
19
|
+
description: 'Git hook file reference (potential hook exploitation)',
|
|
20
|
+
},
|
|
21
|
+
// npm scripts that run arbitrary commands
|
|
22
|
+
{
|
|
23
|
+
pattern: /["'](?:preinstall|postinstall|preuninstall|postuninstall|prepublish|prepare)["']\s*:\s*["'][^"']*(?:curl|wget|bash|sh|node\s+-e|python\s+-c)[^"']*["']/g,
|
|
24
|
+
description: 'npm lifecycle script with shell/network command',
|
|
25
|
+
},
|
|
26
|
+
// CSV injection patterns (formulas that execute when opened in spreadsheets)
|
|
27
|
+
{
|
|
28
|
+
pattern: /(?:^|[,|;])\s*[=+@-]\s*(?:cmd|system|exec|call)\s*\(/gm,
|
|
29
|
+
description: 'CSV injection formula (potential code execution in spreadsheets)',
|
|
30
|
+
},
|
|
31
|
+
// Typosquatting indicators — instructions to install packages with unusual names
|
|
32
|
+
{
|
|
33
|
+
pattern: /(?:npm\s+install|pip\s+install)\s+(?:[a-z]+-[a-z]+-[a-z]+-[a-z]+|[a-z]{1,3}-[a-z]+)\s/g,
|
|
34
|
+
description: 'Package installation with potentially typosquatted name (very short or heavily hyphenated)',
|
|
35
|
+
},
|
|
36
|
+
// Makefile or shell script downloading and executing
|
|
37
|
+
{
|
|
38
|
+
pattern: /(?:make|\.\/\w+\.sh)\b.*&&.*(?:curl|wget)\s+.*\|\s*(?:ba)?sh/g,
|
|
39
|
+
description: 'Build script downloading and executing remote code',
|
|
40
|
+
},
|
|
41
|
+
// npm/pip install from git URL (bypasses registry security)
|
|
42
|
+
{
|
|
43
|
+
pattern: /(?:npm\s+install|pip\s+install)\s+(?:git\+)?https?:\/\/(?!github\.com\/|gitlab\.com\/|bitbucket\.org\/)[^\s]+/g,
|
|
44
|
+
description: 'Package installation from non-standard git URL',
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
exports.supplyChainRule = {
|
|
48
|
+
id: 'supply-chain',
|
|
49
|
+
category: 'supply-chain',
|
|
50
|
+
description: 'Detects supply chain attack patterns — untrusted registries, hook exploitation, CSV injection',
|
|
51
|
+
defaultSeverity: 'medium',
|
|
52
|
+
detect(context) {
|
|
53
|
+
const findings = [];
|
|
54
|
+
const codeBlockRanges = (0, code_block_context_1.parseCodeBlockRanges)(context.body);
|
|
55
|
+
for (const { pattern, description } of SUPPLY_CHAIN_PATTERNS) {
|
|
56
|
+
findings.push(...(0, match_utils_1.matchPattern)(context.body, pattern, codeBlockRanges, 'supply-chain', 'supply-chain', description, 'medium'));
|
|
57
|
+
}
|
|
58
|
+
return findings;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=supply-chain.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"supply-chain.js","sourceRoot":"","sources":["../../../src/security-scanner/rules/supply-chain.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAC7D,gDAA8C;AAG9C;;;GAGG;AACH,MAAM,qBAAqB,GAA+C;IACxE,6DAA6D;IAC7D;QACE,OAAO,EACL,uJAAuJ;QACzJ,WAAW,EAAE,qDAAqD;KACnE;IACD,wDAAwD;IACxD;QACE,OAAO,EACL,8GAA8G;QAChH,WAAW,EAAE,uDAAuD;KACrE;IACD,0CAA0C;IAC1C;QACE,OAAO,EACL,yJAAyJ;QAC3J,WAAW,EAAE,iDAAiD;KAC/D;IACD,6EAA6E;IAC7E;QACE,OAAO,EAAE,wDAAwD;QACjE,WAAW,EAAE,kEAAkE;KAChF;IACD,iFAAiF;IACjF;QACE,OAAO,EACL,wFAAwF;QAC1F,WAAW,EACT,4FAA4F;KAC/F;IACD,qDAAqD;IACrD;QACE,OAAO,EAAE,+DAA+D;QACxE,WAAW,EAAE,oDAAoD;KAClE;IACD,4DAA4D;IAC5D;QACE,OAAO,EACL,gHAAgH;QAClH,WAAW,EAAE,gDAAgD;KAC9D;CACF,CAAC;AAEW,QAAA,eAAe,GAAiB;IAC3C,EAAE,EAAE,cAAc;IAClB,QAAQ,EAAE,cAAc;IACxB,WAAW,EACT,+FAA+F;IACjG,eAAe,EAAE,QAAQ;IACzB,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,MAAM,eAAe,GAAG,IAAA,yCAAoB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE3D,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,qBAAqB,EAAE,CAAC;YAC7D,QAAQ,CAAC,IAAI,CACX,GAAG,IAAA,0BAAY,EACb,OAAO,CAAC,IAAI,EACZ,OAAO,EACP,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,EACX,QAAQ,CACT,CACF,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unicode-attacks.d.ts","sourceRoot":"","sources":["../../../src/security-scanner/rules/unicode-attacks.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,YAAY,EAAoB,MAAM,UAAU,CAAC;AAuDhF,eAAO,MAAM,kBAAkB,EAAE,YAkChC,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unicodeAttacksRule = void 0;
|
|
4
|
+
const code_block_context_1 = require("../code-block-context");
|
|
5
|
+
/**
|
|
6
|
+
* Detects suspicious Unicode characters that can be used to hide text,
|
|
7
|
+
* create visually misleading content, or smuggle instructions.
|
|
8
|
+
*
|
|
9
|
+
* Note: We use individual character alternation instead of character classes
|
|
10
|
+
* for zero-width characters because some (like ZWJ U+200D) are joiners that
|
|
11
|
+
* compose emoji sequences, and biome's `noMisleadingCharacterClass` rule
|
|
12
|
+
* flags them inside character classes.
|
|
13
|
+
*/
|
|
14
|
+
const UNICODE_ATTACK_PATTERNS = [
|
|
15
|
+
// Zero-width characters (ZWSP, ZWNJ, ZWJ, zero-width no-break space)
|
|
16
|
+
// Using alternation instead of character class to avoid noMisleadingCharacterClass
|
|
17
|
+
{
|
|
18
|
+
pattern: /\u200B|\u200C|\u200D|\uFEFF/g,
|
|
19
|
+
description: 'Zero-width character detected (potential hidden text)',
|
|
20
|
+
severity: 'high',
|
|
21
|
+
},
|
|
22
|
+
// Unicode Tags Block (U+E0001-U+E007F) — used for invisible text smuggling
|
|
23
|
+
{
|
|
24
|
+
pattern: /[\u{E0001}-\u{E007F}]/gu,
|
|
25
|
+
description: 'Unicode Tags Block character (invisible text smuggling)',
|
|
26
|
+
severity: 'critical',
|
|
27
|
+
},
|
|
28
|
+
// Right-to-left override/embedding (text direction attacks)
|
|
29
|
+
{
|
|
30
|
+
pattern: /[\u202A-\u202E\u2066-\u2069]/g,
|
|
31
|
+
description: 'Bidirectional text override character (visual spoofing)',
|
|
32
|
+
severity: 'high',
|
|
33
|
+
},
|
|
34
|
+
// Interlinear annotation markers
|
|
35
|
+
{
|
|
36
|
+
pattern: /[\uFFF9-\uFFFB]/g,
|
|
37
|
+
description: 'Interlinear annotation character',
|
|
38
|
+
severity: 'medium',
|
|
39
|
+
},
|
|
40
|
+
// Homoglyph-heavy sequences — Cyrillic/Greek characters in otherwise Latin text
|
|
41
|
+
{
|
|
42
|
+
pattern: /[a-zA-Z]+[\u0400-\u04FF]+|[\u0400-\u04FF]+[a-zA-Z]+/g,
|
|
43
|
+
description: 'Mixed Latin/Cyrillic script (potential homoglyph attack)',
|
|
44
|
+
severity: 'medium',
|
|
45
|
+
},
|
|
46
|
+
// Object replacement character that can hide content
|
|
47
|
+
{
|
|
48
|
+
pattern: /\uFFFC/g,
|
|
49
|
+
description: 'Object replacement character',
|
|
50
|
+
severity: 'low',
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
exports.unicodeAttacksRule = {
|
|
54
|
+
id: 'unicode-attacks',
|
|
55
|
+
category: 'unicode-attacks',
|
|
56
|
+
description: 'Detects suspicious Unicode characters — zero-width chars, bidi overrides, Tags Block, homoglyphs',
|
|
57
|
+
defaultSeverity: 'high',
|
|
58
|
+
detect(context) {
|
|
59
|
+
const findings = [];
|
|
60
|
+
const codeBlockRanges = (0, code_block_context_1.parseCodeBlockRanges)(context.body);
|
|
61
|
+
for (const { pattern, description, severity } of UNICODE_ATTACK_PATTERNS) {
|
|
62
|
+
// matchAll requires a fresh regex or one with global flag
|
|
63
|
+
const globalPattern = pattern.global
|
|
64
|
+
? new RegExp(pattern.source, pattern.flags)
|
|
65
|
+
: new RegExp(pattern.source, `${pattern.flags}g`);
|
|
66
|
+
for (const match of context.body.matchAll(globalPattern)) {
|
|
67
|
+
const line = (0, code_block_context_1.getLineNumber)(context.body, match.index ?? 0);
|
|
68
|
+
const inCodeBlock = (0, code_block_context_1.isLineInCodeBlock)(line, codeBlockRanges);
|
|
69
|
+
findings.push({
|
|
70
|
+
ruleId: 'unicode-attacks',
|
|
71
|
+
category: 'unicode-attacks',
|
|
72
|
+
severity: inCodeBlock ? 'info' : severity,
|
|
73
|
+
message: `Unicode attack: ${description}`,
|
|
74
|
+
evidence: `U+${match[0].codePointAt(0)?.toString(16).toUpperCase().padStart(4, '0')}`,
|
|
75
|
+
line,
|
|
76
|
+
inCodeBlock,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return findings;
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=unicode-attacks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unicode-attacks.js","sourceRoot":"","sources":["../../../src/security-scanner/rules/unicode-attacks.ts"],"names":[],"mappings":";;;AAAA,8DAA+F;AAG/F;;;;;;;;GAQG;AACH,MAAM,uBAAuB,GAIvB;IACJ,qEAAqE;IACrE,mFAAmF;IACnF;QACE,OAAO,EAAE,8BAA8B;QACvC,WAAW,EAAE,uDAAuD;QACpE,QAAQ,EAAE,MAAM;KACjB;IACD,2EAA2E;IAC3E;QACE,OAAO,EAAE,yBAAyB;QAClC,WAAW,EAAE,yDAAyD;QACtE,QAAQ,EAAE,UAAU;KACrB;IACD,4DAA4D;IAC5D;QACE,OAAO,EAAE,+BAA+B;QACxC,WAAW,EAAE,yDAAyD;QACtE,QAAQ,EAAE,MAAM;KACjB;IACD,iCAAiC;IACjC;QACE,OAAO,EAAE,kBAAkB;QAC3B,WAAW,EAAE,kCAAkC;QAC/C,QAAQ,EAAE,QAAQ;KACnB;IACD,gFAAgF;IAChF;QACE,OAAO,EAAE,sDAAsD;QAC/D,WAAW,EAAE,0DAA0D;QACvE,QAAQ,EAAE,QAAQ;KACnB;IACD,qDAAqD;IACrD;QACE,OAAO,EAAE,SAAS;QAClB,WAAW,EAAE,8BAA8B;QAC3C,QAAQ,EAAE,KAAK;KAChB;CACF,CAAC;AAEW,QAAA,kBAAkB,GAAiB;IAC9C,EAAE,EAAE,iBAAiB;IACrB,QAAQ,EAAE,iBAAiB;IAC3B,WAAW,EACT,kGAAkG;IACpG,eAAe,EAAE,MAAM;IACvB,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,MAAM,eAAe,GAAG,IAAA,yCAAoB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE3D,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,uBAAuB,EAAE,CAAC;YACzE,0DAA0D;YAC1D,MAAM,aAAa,GAAG,OAAO,CAAC,MAAM;gBAClC,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC;gBAC3C,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC;YAEpD,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,CAAC;gBACzD,MAAM,IAAI,GAAG,IAAA,kCAAa,EAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;gBAC3D,MAAM,WAAW,GAAG,IAAA,sCAAiB,EAAC,IAAI,EAAE,eAAe,CAAC,CAAC;gBAE7D,QAAQ,CAAC,IAAI,CAAC;oBACZ,MAAM,EAAE,iBAAiB;oBACzB,QAAQ,EAAE,iBAAiB;oBAC3B,QAAQ,EAAE,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ;oBACzC,OAAO,EAAE,mBAAmB,WAAW,EAAE;oBACzC,QAAQ,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE;oBACrF,IAAI;oBACJ,WAAW;iBACZ,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-threats.d.ts","sourceRoot":"","sources":["../../../src/security-scanner/rules/url-threats.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,YAAY,EAAE,MAAM,UAAU,CAAC;AA+D9D,eAAO,MAAM,cAAc,EAAE,YA6C5B,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.urlThreatsRule = void 0;
|
|
4
|
+
const code_block_context_1 = require("../code-block-context");
|
|
5
|
+
const match_utils_1 = require("../match-utils");
|
|
6
|
+
/**
|
|
7
|
+
* URL shortener and redirect service domains that can disguise malicious destinations.
|
|
8
|
+
*/
|
|
9
|
+
const URL_SHORTENER_DOMAINS = [
|
|
10
|
+
'bit.ly',
|
|
11
|
+
'tinyurl.com',
|
|
12
|
+
't.co',
|
|
13
|
+
'goo.gl',
|
|
14
|
+
'ow.ly',
|
|
15
|
+
'is.gd',
|
|
16
|
+
'buff.ly',
|
|
17
|
+
'adf.ly',
|
|
18
|
+
'bl.ink',
|
|
19
|
+
'lnkd.in',
|
|
20
|
+
'soo.gd',
|
|
21
|
+
'rb.gy',
|
|
22
|
+
's.id',
|
|
23
|
+
'v.gd',
|
|
24
|
+
'clck.ru',
|
|
25
|
+
'shorturl.at',
|
|
26
|
+
'cutt.ly',
|
|
27
|
+
];
|
|
28
|
+
/**
|
|
29
|
+
* Patterns for URL-based threats — shorteners, punycode, suspicious TLDs,
|
|
30
|
+
* and IP-based URLs that may disguise malicious destinations.
|
|
31
|
+
*/
|
|
32
|
+
const URL_THREAT_PATTERNS = [
|
|
33
|
+
// Punycode domains (internationalized domain names that can mimic legitimate domains)
|
|
34
|
+
{
|
|
35
|
+
pattern: /https?:\/\/xn--[a-z0-9-]+\.[a-z]{2,}/gi,
|
|
36
|
+
description: 'Punycode domain (potential homograph attack)',
|
|
37
|
+
},
|
|
38
|
+
// IP address URLs (decimal)
|
|
39
|
+
{
|
|
40
|
+
pattern: /https?:\/\/\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}(?::\d+)?(?:\/[^\s]*)?/g,
|
|
41
|
+
description: 'IP-address URL (no domain name — potential evasion)',
|
|
42
|
+
},
|
|
43
|
+
// IP address URLs (decimal-encoded single integer, e.g., http://2130706433)
|
|
44
|
+
{
|
|
45
|
+
pattern: /https?:\/\/\d{8,10}(?:\/[^\s]*)?/g,
|
|
46
|
+
description: 'Decimal-encoded IP URL (obfuscated destination)',
|
|
47
|
+
},
|
|
48
|
+
// Hex-encoded URL
|
|
49
|
+
{
|
|
50
|
+
pattern: /https?:\/\/0x[0-9a-fA-F]+(?:\/[^\s]*)?/g,
|
|
51
|
+
description: 'Hex-encoded IP URL (obfuscated destination)',
|
|
52
|
+
},
|
|
53
|
+
// URLs with excessive redirects via query params
|
|
54
|
+
{
|
|
55
|
+
pattern: /https?:\/\/[^\s]*(?:redirect|redir|goto|next|return|url|continue|destination)\s*=\s*https?(?:%3A|:)/gi,
|
|
56
|
+
description: 'URL with redirect parameter (potential open redirect)',
|
|
57
|
+
},
|
|
58
|
+
// URLs with @ symbol (credential stuffing in URL)
|
|
59
|
+
{
|
|
60
|
+
pattern: /https?:\/\/[^@\s]+@[^@\s]+\.[a-z]{2,}/gi,
|
|
61
|
+
description: 'URL with embedded credentials (user@host format)',
|
|
62
|
+
},
|
|
63
|
+
];
|
|
64
|
+
exports.urlThreatsRule = {
|
|
65
|
+
id: 'url-threats',
|
|
66
|
+
category: 'url-threats',
|
|
67
|
+
description: 'Detects URL-based threats — shorteners, punycode domains, IP-based URLs, open redirects',
|
|
68
|
+
defaultSeverity: 'medium',
|
|
69
|
+
detect(context) {
|
|
70
|
+
const findings = [];
|
|
71
|
+
const codeBlockRanges = (0, code_block_context_1.parseCodeBlockRanges)(context.body);
|
|
72
|
+
// Check for URL shorteners
|
|
73
|
+
const shortenerPattern = new RegExp(`https?:\\/\\/(?:${URL_SHORTENER_DOMAINS.map((d) => d.replace(/\./g, '\\.')).join('|')})\\/[^\\s"')<]+`, 'gi');
|
|
74
|
+
findings.push(...(0, match_utils_1.matchPattern)(context.body, shortenerPattern, codeBlockRanges, 'url-threats', 'url-threats', 'Shortened URL (destination unknown — could disguise malicious target)', 'medium'));
|
|
75
|
+
// Check other URL threat patterns
|
|
76
|
+
for (const { pattern, description } of URL_THREAT_PATTERNS) {
|
|
77
|
+
findings.push(...(0, match_utils_1.matchPattern)(context.body, pattern, codeBlockRanges, 'url-threats', 'url-threats', description, 'medium'));
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=url-threats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-threats.js","sourceRoot":"","sources":["../../../src/security-scanner/rules/url-threats.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAC7D,gDAA8C;AAG9C;;GAEG;AACH,MAAM,qBAAqB,GAAG;IAC5B,QAAQ;IACR,aAAa;IACb,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,SAAS;IACT,QAAQ;IACR,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,OAAO;IACP,MAAM;IACN,MAAM;IACN,SAAS;IACT,aAAa;IACb,SAAS;CACV,CAAC;AAEF;;;GAGG;AACH,MAAM,mBAAmB,GAA+C;IACtE,sFAAsF;IACtF;QACE,OAAO,EAAE,wCAAwC;QACjD,WAAW,EAAE,8CAA8C;KAC5D;IACD,4BAA4B;IAC5B;QACE,OAAO,EAAE,sEAAsE;QAC/E,WAAW,EAAE,qDAAqD;KACnE;IACD,4EAA4E;IAC5E;QACE,OAAO,EAAE,mCAAmC;QAC5C,WAAW,EAAE,iDAAiD;KAC/D;IACD,kBAAkB;IAClB;QACE,OAAO,EAAE,yCAAyC;QAClD,WAAW,EAAE,6CAA6C;KAC3D;IACD,iDAAiD;IACjD;QACE,OAAO,EACL,uGAAuG;QACzG,WAAW,EAAE,uDAAuD;KACrE;IACD,kDAAkD;IAClD;QACE,OAAO,EAAE,yCAAyC;QAClD,WAAW,EAAE,kDAAkD;KAChE;CACF,CAAC;AAEW,QAAA,cAAc,GAAiB;IAC1C,EAAE,EAAE,aAAa;IACjB,QAAQ,EAAE,aAAa;IACvB,WAAW,EACT,yFAAyF;IAC3F,eAAe,EAAE,QAAQ;IACzB,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,MAAM,eAAe,GAAG,IAAA,yCAAoB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE3D,2BAA2B;QAC3B,MAAM,gBAAgB,GAAG,IAAI,MAAM,CACjC,mBAAmB,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,iBAAiB,EACvG,IAAI,CACL,CAAC;QAEF,QAAQ,CAAC,IAAI,CACX,GAAG,IAAA,0BAAY,EACb,OAAO,CAAC,IAAI,EACZ,gBAAgB,EAChB,eAAe,EACf,aAAa,EACb,aAAa,EACb,uEAAuE,EACvE,QAAQ,CACT,CACF,CAAC;QAEF,kCAAkC;QAClC,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,mBAAmB,EAAE,CAAC;YAC3D,QAAQ,CAAC,IAAI,CACX,GAAG,IAAA,0BAAY,EACb,OAAO,CAAC,IAAI,EACZ,OAAO,EACP,eAAe,EACf,aAAa,EACb,aAAa,EACb,WAAW,EACX,QAAQ,CACT,CACF,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xss-html-injection.d.ts","sourceRoot":"","sources":["../../../src/security-scanner/rules/xss-html-injection.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,YAAY,EAAE,MAAM,UAAU,CAAC;AAiE9D,eAAO,MAAM,oBAAoB,EAAE,YAyBlC,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.xssHtmlInjectionRule = void 0;
|
|
4
|
+
const code_block_context_1 = require("../code-block-context");
|
|
5
|
+
const match_utils_1 = require("../match-utils");
|
|
6
|
+
/**
|
|
7
|
+
* Patterns for XSS and HTML injection attacks in markdown.
|
|
8
|
+
* These detect script tags, event handlers, and dangerous URI schemes
|
|
9
|
+
* that could execute code when rendered.
|
|
10
|
+
*/
|
|
11
|
+
const XSS_HTML_PATTERNS = [
|
|
12
|
+
// Script tags (including obfuscated variants)
|
|
13
|
+
{
|
|
14
|
+
pattern: /<\/?script\b[^>]*>/gi,
|
|
15
|
+
description: 'Script tag detected',
|
|
16
|
+
},
|
|
17
|
+
// Event handler attributes (onclick, onerror, onload, etc.)
|
|
18
|
+
{
|
|
19
|
+
pattern: /<\w+[^>]*\bon\w+\s*=\s*["'][^"']*["'][^>]*>/gi,
|
|
20
|
+
description: 'HTML element with inline event handler',
|
|
21
|
+
},
|
|
22
|
+
// javascript: URI scheme
|
|
23
|
+
{
|
|
24
|
+
pattern: /(?:href|src|action|formaction|data)\s*=\s*["']?\s*javascript\s*:/gi,
|
|
25
|
+
description: 'JavaScript URI scheme in HTML attribute',
|
|
26
|
+
},
|
|
27
|
+
// data: URI with script content
|
|
28
|
+
{
|
|
29
|
+
pattern: /(?:href|src)\s*=\s*["']?\s*data\s*:\s*text\/html/gi,
|
|
30
|
+
description: 'Data URI with HTML content (potential XSS)',
|
|
31
|
+
},
|
|
32
|
+
// Markdown link with javascript: URI
|
|
33
|
+
{
|
|
34
|
+
pattern: /\[[^\]]*\]\(\s*javascript\s*:[^)]*\)/gi,
|
|
35
|
+
description: 'Markdown link with javascript: URI',
|
|
36
|
+
},
|
|
37
|
+
// iframe injection
|
|
38
|
+
{
|
|
39
|
+
pattern: /<iframe\b[^>]*>/gi,
|
|
40
|
+
description: 'Iframe injection',
|
|
41
|
+
},
|
|
42
|
+
// object/embed tags (can execute arbitrary content)
|
|
43
|
+
{
|
|
44
|
+
pattern: /<(?:object|embed|applet)\b[^>]*>/gi,
|
|
45
|
+
description: 'Object/embed/applet tag (potential code execution)',
|
|
46
|
+
},
|
|
47
|
+
// SVG with script or event handlers
|
|
48
|
+
{
|
|
49
|
+
pattern: /<svg\b[^>]*>[\s\S]*?(?:<script|on\w+=)/gi,
|
|
50
|
+
description: 'SVG element with embedded script or event handler',
|
|
51
|
+
},
|
|
52
|
+
// CSS expression/behavior (IE-specific but still relevant for detection)
|
|
53
|
+
{
|
|
54
|
+
pattern: /expression\s*\([^)]*\)|behavior\s*:\s*url\s*\(/gi,
|
|
55
|
+
description: 'CSS expression or behavior (potential code execution)',
|
|
56
|
+
},
|
|
57
|
+
// Meta refresh redirect
|
|
58
|
+
{
|
|
59
|
+
pattern: /<meta[^>]*http-equiv\s*=\s*["']?refresh["']?[^>]*>/gi,
|
|
60
|
+
description: 'Meta refresh redirect',
|
|
61
|
+
},
|
|
62
|
+
// Form tags (potential for phishing)
|
|
63
|
+
{
|
|
64
|
+
pattern: /<form\b[^>]*action\s*=\s*["']https?:\/\/[^"']*["'][^>]*>/gi,
|
|
65
|
+
description: 'HTML form with external action URL (potential phishing)',
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
exports.xssHtmlInjectionRule = {
|
|
69
|
+
id: 'xss-html-injection',
|
|
70
|
+
category: 'xss-html-injection',
|
|
71
|
+
description: 'Detects XSS and HTML injection — script tags, event handlers, dangerous URIs',
|
|
72
|
+
defaultSeverity: 'high',
|
|
73
|
+
detect(context) {
|
|
74
|
+
const findings = [];
|
|
75
|
+
const codeBlockRanges = (0, code_block_context_1.parseCodeBlockRanges)(context.body);
|
|
76
|
+
for (const { pattern, description } of XSS_HTML_PATTERNS) {
|
|
77
|
+
findings.push(...(0, match_utils_1.matchPattern)(context.body, pattern, codeBlockRanges, 'xss-html-injection', 'xss-html-injection', description, 'high'));
|
|
78
|
+
}
|
|
79
|
+
return findings;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=xss-html-injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"xss-html-injection.js","sourceRoot":"","sources":["../../../src/security-scanner/rules/xss-html-injection.ts"],"names":[],"mappings":";;;AAAA,8DAA6D;AAC7D,gDAA8C;AAG9C;;;;GAIG;AACH,MAAM,iBAAiB,GAA+C;IACpE,8CAA8C;IAC9C;QACE,OAAO,EAAE,sBAAsB;QAC/B,WAAW,EAAE,qBAAqB;KACnC;IACD,4DAA4D;IAC5D;QACE,OAAO,EAAE,+CAA+C;QACxD,WAAW,EAAE,wCAAwC;KACtD;IACD,yBAAyB;IACzB;QACE,OAAO,EAAE,oEAAoE;QAC7E,WAAW,EAAE,yCAAyC;KACvD;IACD,gCAAgC;IAChC;QACE,OAAO,EAAE,oDAAoD;QAC7D,WAAW,EAAE,4CAA4C;KAC1D;IACD,qCAAqC;IACrC;QACE,OAAO,EAAE,wCAAwC;QACjD,WAAW,EAAE,oCAAoC;KAClD;IACD,mBAAmB;IACnB;QACE,OAAO,EAAE,mBAAmB;QAC5B,WAAW,EAAE,kBAAkB;KAChC;IACD,oDAAoD;IACpD;QACE,OAAO,EAAE,oCAAoC;QAC7C,WAAW,EAAE,oDAAoD;KAClE;IACD,oCAAoC;IACpC;QACE,OAAO,EAAE,0CAA0C;QACnD,WAAW,EAAE,mDAAmD;KACjE;IACD,yEAAyE;IACzE;QACE,OAAO,EAAE,kDAAkD;QAC3D,WAAW,EAAE,uDAAuD;KACrE;IACD,wBAAwB;IACxB;QACE,OAAO,EAAE,sDAAsD;QAC/D,WAAW,EAAE,uBAAuB;KACrC;IACD,qCAAqC;IACrC;QACE,OAAO,EAAE,4DAA4D;QACrE,WAAW,EAAE,yDAAyD;KACvE;CACF,CAAC;AAEW,QAAA,oBAAoB,GAAiB;IAChD,EAAE,EAAE,oBAAoB;IACxB,QAAQ,EAAE,oBAAoB;IAC9B,WAAW,EAAE,8EAA8E;IAC3F,eAAe,EAAE,MAAM;IACvB,MAAM,CAAC,OAAO;QACZ,MAAM,QAAQ,GAAsB,EAAE,CAAC;QACvC,MAAM,eAAe,GAAG,IAAA,yCAAoB,EAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAE3D,KAAK,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,IAAI,iBAAiB,EAAE,CAAC;YACzD,QAAQ,CAAC,IAAI,CACX,GAAG,IAAA,0BAAY,EACb,OAAO,CAAC,IAAI,EACZ,OAAO,EACP,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,WAAW,EACX,MAAM,CACP,CACF,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { DossierFrontmatter } from '../types';
|
|
2
|
+
export type SecuritySeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
|
|
3
|
+
export type SecurityCategory = 'prompt-injection' | 'agent-hijacking' | 'dangerous-execution' | 'unicode-attacks' | 'data-exfiltration' | 'xss-html-injection' | 'url-threats' | 'supply-chain';
|
|
4
|
+
export interface SecurityFinding {
|
|
5
|
+
ruleId: string;
|
|
6
|
+
category: SecurityCategory;
|
|
7
|
+
severity: SecuritySeverity;
|
|
8
|
+
message: string;
|
|
9
|
+
/** The matched text or pattern that triggered the finding */
|
|
10
|
+
evidence?: string;
|
|
11
|
+
/** Approximate line number in the body (1-based) */
|
|
12
|
+
line?: number;
|
|
13
|
+
/** Whether the finding is inside a fenced code block (lower confidence) */
|
|
14
|
+
inCodeBlock: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface SecurityRuleContext {
|
|
17
|
+
frontmatter: DossierFrontmatter;
|
|
18
|
+
body: string;
|
|
19
|
+
raw: string;
|
|
20
|
+
}
|
|
21
|
+
export interface SecurityRule {
|
|
22
|
+
id: string;
|
|
23
|
+
category: SecurityCategory;
|
|
24
|
+
description: string;
|
|
25
|
+
defaultSeverity: SecuritySeverity;
|
|
26
|
+
detect(context: SecurityRuleContext): SecurityFinding[];
|
|
27
|
+
}
|
|
28
|
+
export type SecurityRuleSeverityOverride = SecuritySeverity | 'off';
|
|
29
|
+
export interface SecurityScanConfig {
|
|
30
|
+
rules: Record<string, SecurityRuleSeverityOverride>;
|
|
31
|
+
/** Minimum severity to include in results (default: 'info') */
|
|
32
|
+
minSeverity?: SecuritySeverity;
|
|
33
|
+
}
|
|
34
|
+
export interface SecurityReport {
|
|
35
|
+
file?: string;
|
|
36
|
+
findings: SecurityFinding[];
|
|
37
|
+
criticalCount: number;
|
|
38
|
+
highCount: number;
|
|
39
|
+
mediumCount: number;
|
|
40
|
+
lowCount: number;
|
|
41
|
+
infoCount: number;
|
|
42
|
+
/** Overall risk verdict */
|
|
43
|
+
verdict: 'PASS' | 'WARN' | 'FAIL';
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/security-scanner/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;AAE/E,MAAM,MAAM,gBAAgB,GACxB,kBAAkB,GAClB,iBAAiB,GACjB,qBAAqB,GACrB,iBAAiB,GACjB,mBAAmB,GACnB,oBAAoB,GACpB,aAAa,GACb,cAAc,CAAC;AAEnB,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2EAA2E;IAC3E,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,kBAAkB,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,gBAAgB,CAAC;IAClC,MAAM,CAAC,OAAO,EAAE,mBAAmB,GAAG,eAAe,EAAE,CAAC;CACzD;AAED,MAAM,MAAM,4BAA4B,GAAG,gBAAgB,GAAG,KAAK,CAAC;AAEpE,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,4BAA4B,CAAC,CAAC;IACpD,+DAA+D;IAC/D,WAAW,CAAC,EAAE,gBAAgB,CAAC;CAChC;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;CACnC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/security-scanner/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
export declare const VALID_TRACE_STATUSES: readonly ["running", "success", "failed", "cancelled"];
|
|
2
|
+
export type TraceStatus = (typeof VALID_TRACE_STATUSES)[number];
|
|
3
|
+
export interface TraceInput {
|
|
4
|
+
trace_id: string;
|
|
5
|
+
dossier: {
|
|
6
|
+
title: string;
|
|
7
|
+
version: string;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
};
|
|
10
|
+
agent?: {
|
|
11
|
+
name?: string;
|
|
12
|
+
version?: string;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
15
|
+
started_at: string;
|
|
16
|
+
completed_at?: string;
|
|
17
|
+
duration_ms?: number;
|
|
18
|
+
status: TraceStatus;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
}
|
|
21
|
+
export interface TraceUpdate {
|
|
22
|
+
status?: TraceStatus;
|
|
23
|
+
completed_at?: string;
|
|
24
|
+
duration_ms?: number;
|
|
25
|
+
[key: string]: unknown;
|
|
26
|
+
}
|
|
27
|
+
export interface StepInput {
|
|
28
|
+
step_id: string;
|
|
29
|
+
type: string;
|
|
30
|
+
timestamp?: string;
|
|
31
|
+
[key: string]: unknown;
|
|
32
|
+
}
|
|
33
|
+
export interface TraceRecorderOptions {
|
|
34
|
+
url?: string;
|
|
35
|
+
token?: string;
|
|
36
|
+
fetch?: typeof fetch;
|
|
37
|
+
}
|
|
38
|
+
export interface TraceRecorder {
|
|
39
|
+
readonly enabled: boolean;
|
|
40
|
+
create(input: TraceInput): Promise<void>;
|
|
41
|
+
appendStep(traceId: string, step: StepInput): Promise<void>;
|
|
42
|
+
complete(traceId: string, update: TraceUpdate): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
export declare function createTraceRecorder(opts?: TraceRecorderOptions): TraceRecorder;
|
|
45
|
+
//# sourceMappingURL=trace-recorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-recorder.d.ts","sourceRoot":"","sources":["../src/trace-recorder.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,oBAAoB,wDAAyD,CAAC;AAC3F,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEhE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACpE,KAAK,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IACnC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5D,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/D;AAED,wBAAgB,mBAAmB,CAAC,IAAI,GAAE,oBAAyB,GAAG,aAAa,CAwClF"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Trace recorder for dossier execution. Opt-in: returns a no-op recorder
|
|
3
|
+
// unless both DOSSIER_TRACE_URL and DOSSIER_TRACE_TOKEN (or the equivalent
|
|
4
|
+
// opts) are provided. Fire-and-forget: network failures are swallowed so
|
|
5
|
+
// tracing never breaks the agent run.
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.VALID_TRACE_STATUSES = void 0;
|
|
8
|
+
exports.createTraceRecorder = createTraceRecorder;
|
|
9
|
+
exports.VALID_TRACE_STATUSES = ['running', 'success', 'failed', 'cancelled'];
|
|
10
|
+
function createTraceRecorder(opts = {}) {
|
|
11
|
+
const url = opts.url ?? process.env.DOSSIER_TRACE_URL ?? '';
|
|
12
|
+
const token = opts.token ?? process.env.DOSSIER_TRACE_TOKEN ?? '';
|
|
13
|
+
const fetchImpl = opts.fetch ?? globalThis.fetch;
|
|
14
|
+
if (!url || !token || !fetchImpl) {
|
|
15
|
+
return {
|
|
16
|
+
enabled: false,
|
|
17
|
+
create: noop,
|
|
18
|
+
appendStep: noop,
|
|
19
|
+
complete: noop,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
const base = url.replace(/\/+$/, '');
|
|
23
|
+
const headers = {
|
|
24
|
+
'content-type': 'application/json',
|
|
25
|
+
authorization: `Bearer ${token}`,
|
|
26
|
+
};
|
|
27
|
+
const send = (method, path, body) => Promise.resolve()
|
|
28
|
+
.then(() => fetchImpl(`${base}${path}`, {
|
|
29
|
+
method,
|
|
30
|
+
headers,
|
|
31
|
+
body: JSON.stringify(body),
|
|
32
|
+
}))
|
|
33
|
+
.then(() => undefined)
|
|
34
|
+
.catch(() => undefined);
|
|
35
|
+
return {
|
|
36
|
+
enabled: true,
|
|
37
|
+
create: (input) => send('POST', '/api/v1/traces', input),
|
|
38
|
+
appendStep: (traceId, step) => send('POST', `/api/v1/traces/${encodeURIComponent(traceId)}/steps`, step),
|
|
39
|
+
complete: (traceId, update) => send('PATCH', `/api/v1/traces/${encodeURIComponent(traceId)}`, update),
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
async function noop() { }
|
|
43
|
+
//# sourceMappingURL=trace-recorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-recorder.js","sourceRoot":"","sources":["../src/trace-recorder.ts"],"names":[],"mappings":";AAAA,yEAAyE;AACzE,2EAA2E;AAC3E,yEAAyE;AACzE,sCAAsC;;;AA2CtC,kDAwCC;AAjFY,QAAA,oBAAoB,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,CAAU,CAAC;AAyC3F,SAAgB,mBAAmB,CAAC,OAA6B,EAAE;IACjE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,EAAE,CAAC;IAC5D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC;IAClE,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC;IAEjD,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACjC,OAAO;YACL,OAAO,EAAE,KAAK;YACd,MAAM,EAAE,IAAI;YACZ,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,IAAI;SACf,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACrC,MAAM,OAAO,GAAG;QACd,cAAc,EAAE,kBAAkB;QAClC,aAAa,EAAE,UAAU,KAAK,EAAE;KACjC,CAAC;IAEF,MAAM,IAAI,GAAG,CAAC,MAAc,EAAE,IAAY,EAAE,IAAa,EAAiB,EAAE,CAC1E,OAAO,CAAC,OAAO,EAAE;SACd,IAAI,CAAC,GAAG,EAAE,CACT,SAAS,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,EAAE;QAC1B,MAAM;QACN,OAAO;QACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;KAC3B,CAAC,CACH;SACA,IAAI,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC;SACrB,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;IAE5B,OAAO;QACL,OAAO,EAAE,IAAI;QACb,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC;QACxD,UAAU,EAAE,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,CAC5B,IAAI,CAAC,MAAM,EAAE,kBAAkB,kBAAkB,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC;QAC3E,QAAQ,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAC5B,IAAI,CAAC,OAAO,EAAE,kBAAkB,kBAAkB,CAAC,OAAO,CAAC,EAAE,EAAE,MAAM,CAAC;KACzE,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,IAAI,KAAmB,CAAC"}
|