@bouncesecurity/aghast 0.0.13

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 (97) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +111 -0
  3. package/config/prompts/generic-instructions.md +56 -0
  4. package/config/prompts/test-cheaper-instructions.md +57 -0
  5. package/dist/check-library.d.ts +87 -0
  6. package/dist/check-library.d.ts.map +1 -0
  7. package/dist/check-library.js +374 -0
  8. package/dist/check-library.js.map +1 -0
  9. package/dist/claude-code-provider.d.ts +26 -0
  10. package/dist/claude-code-provider.d.ts.map +1 -0
  11. package/dist/claude-code-provider.js +247 -0
  12. package/dist/claude-code-provider.js.map +1 -0
  13. package/dist/cli.d.ts +13 -0
  14. package/dist/cli.d.ts.map +1 -0
  15. package/dist/cli.js +78 -0
  16. package/dist/cli.js.map +1 -0
  17. package/dist/colors.d.ts +7 -0
  18. package/dist/colors.d.ts.map +1 -0
  19. package/dist/colors.js +18 -0
  20. package/dist/colors.js.map +1 -0
  21. package/dist/error-codes.d.ts +42 -0
  22. package/dist/error-codes.d.ts.map +1 -0
  23. package/dist/error-codes.js +60 -0
  24. package/dist/error-codes.js.map +1 -0
  25. package/dist/formatters/index.d.ts +10 -0
  26. package/dist/formatters/index.d.ts.map +1 -0
  27. package/dist/formatters/index.js +23 -0
  28. package/dist/formatters/index.js.map +1 -0
  29. package/dist/formatters/json-formatter.d.ts +11 -0
  30. package/dist/formatters/json-formatter.d.ts.map +1 -0
  31. package/dist/formatters/json-formatter.js +11 -0
  32. package/dist/formatters/json-formatter.js.map +1 -0
  33. package/dist/formatters/sarif-formatter.d.ts +18 -0
  34. package/dist/formatters/sarif-formatter.d.ts.map +1 -0
  35. package/dist/formatters/sarif-formatter.js +103 -0
  36. package/dist/formatters/sarif-formatter.js.map +1 -0
  37. package/dist/formatters/types.d.ts +11 -0
  38. package/dist/formatters/types.d.ts.map +1 -0
  39. package/dist/formatters/types.js +6 -0
  40. package/dist/formatters/types.js.map +1 -0
  41. package/dist/index.d.ts +7 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +406 -0
  44. package/dist/index.js.map +1 -0
  45. package/dist/logging.d.ts +26 -0
  46. package/dist/logging.d.ts.map +1 -0
  47. package/dist/logging.js +79 -0
  48. package/dist/logging.js.map +1 -0
  49. package/dist/mock-ai-provider.d.ts +18 -0
  50. package/dist/mock-ai-provider.d.ts.map +1 -0
  51. package/dist/mock-ai-provider.js +28 -0
  52. package/dist/mock-ai-provider.js.map +1 -0
  53. package/dist/new-check.d.ts +13 -0
  54. package/dist/new-check.d.ts.map +1 -0
  55. package/dist/new-check.js +405 -0
  56. package/dist/new-check.js.map +1 -0
  57. package/dist/prompt-template.d.ts +12 -0
  58. package/dist/prompt-template.d.ts.map +1 -0
  59. package/dist/prompt-template.js +35 -0
  60. package/dist/prompt-template.js.map +1 -0
  61. package/dist/provider-registry.d.ts +15 -0
  62. package/dist/provider-registry.d.ts.map +1 -0
  63. package/dist/provider-registry.js +27 -0
  64. package/dist/provider-registry.js.map +1 -0
  65. package/dist/repository-analyzer.d.ts +68 -0
  66. package/dist/repository-analyzer.d.ts.map +1 -0
  67. package/dist/repository-analyzer.js +230 -0
  68. package/dist/repository-analyzer.js.map +1 -0
  69. package/dist/response-parser.d.ts +12 -0
  70. package/dist/response-parser.d.ts.map +1 -0
  71. package/dist/response-parser.js +109 -0
  72. package/dist/response-parser.js.map +1 -0
  73. package/dist/runtime-config.d.ts +15 -0
  74. package/dist/runtime-config.d.ts.map +1 -0
  75. package/dist/runtime-config.js +73 -0
  76. package/dist/runtime-config.js.map +1 -0
  77. package/dist/sarif-parser.d.ts +20 -0
  78. package/dist/sarif-parser.d.ts.map +1 -0
  79. package/dist/sarif-parser.js +76 -0
  80. package/dist/sarif-parser.js.map +1 -0
  81. package/dist/scan-runner.d.ts +29 -0
  82. package/dist/scan-runner.d.ts.map +1 -0
  83. package/dist/scan-runner.js +559 -0
  84. package/dist/scan-runner.js.map +1 -0
  85. package/dist/semgrep-runner.d.ts +25 -0
  86. package/dist/semgrep-runner.d.ts.map +1 -0
  87. package/dist/semgrep-runner.js +100 -0
  88. package/dist/semgrep-runner.js.map +1 -0
  89. package/dist/snippet-extractor.d.ts +25 -0
  90. package/dist/snippet-extractor.d.ts.map +1 -0
  91. package/dist/snippet-extractor.js +56 -0
  92. package/dist/snippet-extractor.js.map +1 -0
  93. package/dist/types.d.ts +206 -0
  94. package/dist/types.d.ts.map +1 -0
  95. package/dist/types.js +19 -0
  96. package/dist/types.js.map +1 -0
  97. package/package.json +55 -0
package/README.md ADDED
@@ -0,0 +1,111 @@
1
+ # AI Guided Hybrid Application Static Testing (AGHAST) - ALPHA VERSION
2
+
3
+ ![Status: Alpha](https://img.shields.io/badge/Status-Alpha-orange)
4
+ [![CI](https://github.com/BounceSecurity/aghast/actions/workflows/ci.yml/badge.svg)](https://github.com/BounceSecurity/aghast/actions/workflows/ci.yml)
5
+ [![License: AGPL v3](https://img.shields.io/badge/License-AGPL_v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
6
+ [![By Bounce Security](https://img.shields.io/badge/By-Bounce_Security-f79421)](https://bouncesecurity.com/)
7
+
8
+ > **Warning**
9
+ > AGHAST is in **early alpha**. APIs, CLI flags, configuration formats, and output schemas may change between releases without notice. Use in production CI/CD pipelines at your own risk.
10
+
11
+ An open source tool that combines static scanning rules with AI prompts to find code-specific and company-specific security issues.
12
+
13
+ Define static rules, security checks as markdown instructions, point AGHAST at a repo, and get structured results (JSON or SARIF).
14
+
15
+ <p align="center">
16
+ <img src="/assets/img/aghastbouncecaption.png" alt="AGHAST" width="50%">
17
+ </p>
18
+
19
+ ## What AGHAST Does
20
+
21
+ You can read the full background to this tool in our blogpost [here](https://bouncesecurity.com/aghast) but, to cut to the chase, AGHAST helps you run three types of checks:
22
+
23
+ - Pure AI scanning rules - let the LLM do all the analysis
24
+ - A combination of a static rule and an AI scanning rule - the sweet spot for most use cases
25
+ - Purely static rules - for completeness, when a traditional static rule is all you need
26
+
27
+ The beauty of the approach is what you *don't* need:
28
+
29
+ - You don't need to modify the code
30
+ - You don't need to build something into the codebase
31
+ - You don't need to write code in the language of the codebase
32
+
33
+ All you need is:
34
+
35
+ - Access to the codebase
36
+ - An understanding of the problem you are trying to discover
37
+ - The ability to write some simple rules
38
+
39
+ There are almost certainly other ways of achieving this, but to our mind, this approach is both straightforward and deterministic.
40
+
41
+ ## Prerequisites
42
+
43
+ - **Node.js 20+**
44
+ - **[Semgrep Community Edition](https://semgrep.dev/docs/getting-started/)** (LGPL-2.1, optional) — only needed for checks that use Semgrep rules
45
+ - **Anthropic API key** — for AI-based checks (not needed for semgrep-only checks)
46
+
47
+ ## Installation
48
+
49
+ See the [Getting Started Guide](docs/getting-started.md) for full installation and setup instructions.
50
+
51
+ ## Quick Start
52
+
53
+ Set your API key, create a check, and run a scan:
54
+
55
+ ```bash
56
+ export ANTHROPIC_API_KEY=your-api-key
57
+ aghast new-check --config-dir ./my-checks
58
+ aghast scan /path/to/target-repo --config-dir ./my-checks
59
+ ```
60
+
61
+ See the [Getting Started Guide](docs/getting-started.md) for a full walkthrough.
62
+
63
+ ## Example Output
64
+
65
+ Results are structured JSON (or SARIF) with per-check status and detailed issues:
66
+
67
+ ```json
68
+ {
69
+ "checks": [
70
+ { "checkId": "aghast-api-authz", "checkName": "API Authorization Check", "status": "FAIL", "issuesFound": 1 },
71
+ { "checkId": "aghast-sql-injection", "checkName": "SQL Injection Prevention", "status": "PASS", "issuesFound": 0 }
72
+ ],
73
+ "issues": [
74
+ {
75
+ "checkId": "aghast-api-authz",
76
+ "checkName": "API Authorization Check",
77
+ "file": "src/api/users.ts",
78
+ "startLine": 45,
79
+ "endLine": 52,
80
+ "description": "Missing authorization check on DELETE endpoint.",
81
+ "codeSnippet": "router.delete('/users/:id', async (req, res) => {"
82
+ }
83
+ ],
84
+ "summary": {
85
+ "totalChecks": 2,
86
+ "passedChecks": 1,
87
+ "failedChecks": 1,
88
+ "flaggedChecks": 0,
89
+ "errorChecks": 0,
90
+ "totalIssues": 1
91
+ }
92
+ }
93
+ ```
94
+
95
+ ## Documentation
96
+
97
+ - [Getting Started](docs/getting-started.md) — installation, setup, and first scan
98
+ - [Scanning](docs/scanning.md) — scan command options, environment variables, output formats
99
+ - [Creating Checks](docs/creating-checks.md) — scaffolding new security checks
100
+ - [Configuration Reference](docs/configuration.md) — check schemas, check types, runtime config
101
+ - [Development](docs/development.md) — setup, building, testing, releasing
102
+
103
+ ## Contributing
104
+
105
+ We welcome bug reports and feature requests via [GitHub Issues](https://github.com/BounceSecurity/aghast/issues). We are not currently accepting pull requests.
106
+
107
+ ## License
108
+
109
+ This project is licensed under the [GNU Affero General Public License v3.0 or later](LICENSE).
110
+
111
+ Copyright (C) 2026 [Bounce Consulting Ltd.](https://bouncesecurity.com/)
@@ -0,0 +1,56 @@
1
+ GENERIC INSTRUCTIONS:
2
+
3
+ You are performing a SPECIFIC security check as defined in the CHECK INSTRUCTIONS below.
4
+
5
+ IMPORTANT:
6
+ - Focus ONLY on what the CHECK INSTRUCTIONS ask you to validate
7
+ - Do NOT perform general security testing or look for unrelated vulnerabilities
8
+ - Do NOT report issues outside the scope of the specific check
9
+ - Follow the CHECK INSTRUCTIONS exactly as written
10
+
11
+ OUTPUT FORMAT:
12
+
13
+ Return your findings in the following JSON format:
14
+
15
+ {
16
+ "issues": [
17
+ {
18
+ "file": "relative/path/to/file.ts",
19
+ "startLine": 40,
20
+ "endLine": 45,
21
+ "description": "Detailed explanation (see requirements below)",
22
+ "dataFlow": [
23
+ { "file": "src/routes/handler.ts", "lineNumber": 12, "label": "User input received from request parameter" },
24
+ { "file": "src/services/query.ts", "lineNumber": 38, "label": "Input passed to SQL query without sanitization" }
25
+ ]
26
+ }
27
+ ]
28
+ }
29
+
30
+ DESCRIPTION FORMATTING REQUIREMENTS:
31
+
32
+ Your description field MUST be detailed and well-structured:
33
+ - Use markdown formatting with headings (## Heading), bullet points, code blocks
34
+ - Use \n for line breaks to create structured, readable content
35
+ - Include an "Attack Scenario" section demonstrating exploitation
36
+ - Include a "Recommendation" section with specific remediation steps
37
+
38
+ DATA FLOW REQUIREMENTS:
39
+
40
+ When the issue involves data flowing through multiple locations (e.g., user input reaching a dangerous sink), include a "dataFlow" array. Each step represents a point in the call stack or data flow:
41
+ - "file": relative path to the source file
42
+ - "lineNumber": the line number at that step
43
+ - "label": a short description of what happens at this point (e.g., "User input received", "Passed to database query")
44
+ - Order steps from source (e.g., user input) to sink (e.g., SQL execution)
45
+ - Omit "dataFlow" entirely if the issue is localized to a single location
46
+
47
+ CRITICAL: Return ONLY valid JSON. No markdown code blocks, no explanations outside the JSON.
48
+
49
+ If no issues found for this SPECIFIC check, return: {"issues": []}
50
+
51
+ If a TARGET LOCATION section appears at the end of this prompt, you must analyze ONLY that specific code location.
52
+
53
+ ---
54
+
55
+ CHECK INSTRUCTIONS:
56
+
@@ -0,0 +1,57 @@
1
+ GENERIC INSTRUCTIONS:
2
+
3
+ You are performing a SPECIFIC security check as defined in the CHECK INSTRUCTIONS below.
4
+
5
+ IMPORTANT:
6
+ - Focus ONLY on what the CHECK INSTRUCTIONS ask you to validate
7
+ - Make sure you read the CHECK INSTRUCTIONS in full and comply with them
8
+ - Do NOT perform general security testing or look for unrelated vulnerabilities
9
+ - Do NOT report issues outside the scope of the specific check
10
+ - Follow the CHECK INSTRUCTIONS exactly as written
11
+
12
+ OUTPUT FORMAT:
13
+
14
+ Return your findings in the following JSON format:
15
+
16
+ {
17
+ "issues": [
18
+ {
19
+ "file": "relative/path/to/file.ts",
20
+ "startLine": 40,
21
+ "endLine": 45,
22
+ "description": "Detailed explanation (see requirements below)",
23
+ "dataFlow": [
24
+ { "file": "src/routes/handler.ts", "lineNumber": 12, "label": "User input received from request parameter" },
25
+ { "file": "src/services/query.ts", "lineNumber": 38, "label": "Input passed to SQL query without sanitization" }
26
+ ]
27
+ }
28
+ ]
29
+ }
30
+
31
+ DESCRIPTION FORMATTING REQUIREMENTS:
32
+
33
+ Your description field MUST be detailed and well-structured:
34
+ - Use markdown formatting with headings (## Heading), bullet points
35
+ - Use \n for line breaks to create structured, readable content
36
+ - No need for "Example Attack" or a "Details" sections
37
+ - Keep description as short as possible.
38
+
39
+ DATA FLOW REQUIREMENTS:
40
+
41
+ When the issue involves data flowing through multiple locations (e.g., user input reaching a dangerous sink), include a "dataFlow" array. Each step represents a point in the call stack or data flow:
42
+ - "file": relative path to the source file
43
+ - "lineNumber": the line number at that step
44
+ - "label": a short description of what happens at this point (e.g., "User input received", "Passed to database query")
45
+ - Order steps from source (e.g., user input) to sink (e.g., SQL execution)
46
+ - Omit "dataFlow" entirely if the issue is localized to a single location
47
+
48
+ CRITICAL: Return ONLY valid JSON. No markdown code blocks, no explanations outside the JSON.
49
+
50
+ If no issues found for this SPECIFIC check, return: {"issues": []}
51
+
52
+ If a TARGET LOCATION section appears at the end of this prompt, you must analyze ONLY that specific code location.
53
+
54
+ ---
55
+
56
+ CHECK INSTRUCTIONS:
57
+
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Check Library / Config Manager.
3
+ * Two-layer config: Layer 1 (registry) maps checks to repos,
4
+ * Layer 2 (<id>.json) defines each check in its own folder.
5
+ * Implements spec Appendix B.1.
6
+ */
7
+ import type { SecurityCheck, CheckDetails, CheckRegistryEntry, CheckDefinition } from './types.js';
8
+ export interface CheckRegistry {
9
+ checks: CheckRegistryEntry[];
10
+ }
11
+ /**
12
+ * Load and parse the Layer 1 registry from <configDir>/checks-config.json.
13
+ * Throws on missing file, malformed JSON, or invalid structure.
14
+ */
15
+ export declare function loadCheckRegistry(configDir: string): Promise<CheckRegistry>;
16
+ /**
17
+ * Load and parse a Layer 2 check definition from <checkFolderPath>/<id>.json.
18
+ * Throws on missing file, malformed JSON, or missing required fields.
19
+ */
20
+ export declare function loadCheckDefinition(checkFolderPath: string): Promise<CheckDefinition>;
21
+ /**
22
+ * Scan check directories for subfolders containing <id>.json.
23
+ * Returns a map of check id → folder path.
24
+ */
25
+ export declare function discoverCheckFolders(checksDirs: string[]): Promise<Map<string, string>>;
26
+ /**
27
+ * Merge Layer 1 registry entries with Layer 2 check definitions.
28
+ * Resolves instructionsFile and checkTarget.rules paths relative to check folder.
29
+ * Throws if a registry entry has no matching check folder.
30
+ */
31
+ export declare function resolveChecks(registry: CheckRegistry, checkFolders: Map<string, string>): Promise<SecurityCheck[]>;
32
+ export interface CheckLibraryConfig {
33
+ checks: SecurityCheck[];
34
+ }
35
+ /**
36
+ * Load and parse a flat JSON config file (old format).
37
+ * Kept for backward compatibility with existing test fixtures.
38
+ */
39
+ export declare function loadConfig(configPath: string): Promise<CheckLibraryConfig>;
40
+ export interface ValidationResult {
41
+ valid: boolean;
42
+ errors: string[];
43
+ }
44
+ /**
45
+ * Validate a single SecurityCheck definition.
46
+ * Checks that id is present and non-empty, and instructionsFile exists on disk.
47
+ * basePath is used to resolve instructionsFile if it's a relative path.
48
+ * If instructionsFile is already absolute, basePath is ignored.
49
+ */
50
+ export declare function validateCheck(check: SecurityCheck, basePath: string): Promise<ValidationResult>;
51
+ export { normalizeRepoPath } from './repository-analyzer.js';
52
+ /**
53
+ * Check if a single check matches the given repository URL/path.
54
+ * Empty repositories array matches all repos.
55
+ * Uses bidirectional substring matching on normalized paths.
56
+ */
57
+ export declare function checkMatchesRepository(check: SecurityCheck, repositoryUrl: string): boolean;
58
+ /**
59
+ * Filter checks to those matching the given repository URL/path.
60
+ * Also filters out disabled checks (enabled === false).
61
+ */
62
+ export declare function filterChecksForRepository(checks: SecurityCheck[], repositoryUrl: string): SecurityCheck[];
63
+ /**
64
+ * Parse a markdown check file into CheckDetails.
65
+ * Extracts name from first ### heading, overview from #### Overview section.
66
+ */
67
+ export declare function parseCheckMarkdown(id: string, markdown: string): CheckDetails;
68
+ /**
69
+ * Load check instructions from the markdown file referenced by a SecurityCheck.
70
+ * Resolves instructionsFile relative to basePath (or uses absolute path if already resolved).
71
+ */
72
+ export declare function loadCheckDetails(check: SecurityCheck, basePath: string): Promise<CheckDetails>;
73
+ /**
74
+ * Filter files to those matching applicablePaths globs.
75
+ * If applicablePaths is undefined or empty, returns all files.
76
+ */
77
+ export declare function filterApplicablePaths(files: string[], applicablePaths?: string[]): string[];
78
+ /**
79
+ * Filter out files matching excludedPaths globs.
80
+ * If excludedPaths is undefined or empty, returns all files.
81
+ */
82
+ export declare function filterExcludedPaths(files: string[], excludedPaths?: string[]): string[];
83
+ /**
84
+ * Apply both applicablePaths and excludedPaths filtering.
85
+ */
86
+ export declare function filterCheckPaths(files: string[], check: SecurityCheck): string[];
87
+ //# sourceMappingURL=check-library.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-library.d.ts","sourceRoot":"","sources":["../src/check-library.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,aAAa,EACb,YAAY,EACZ,kBAAkB,EAClB,eAAe,EAChB,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,kBAAkB,EAAE,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA0DjF;AAID;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,eAAe,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA8E3F;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,MAAM,EAAE,GACnB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CA2B9B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,QAAQ,EAAE,aAAa,EACvB,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC,aAAa,EAAE,CAAC,CAmD1B;AAID,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,aAAa,EAAE,CAAC;CACzB;AAED;;;GAGG;AACH,wBAAsB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiChF;AAID,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,gBAAgB,CAAC,CAyB3B;AAKD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,EACpB,aAAa,EAAE,MAAM,GACpB,OAAO,CAcT;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,aAAa,EAAE,EACvB,aAAa,EAAE,MAAM,GACpB,aAAa,EAAE,CAIjB;AAID;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAoB7E;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAgBvB;AAOD;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,MAAM,EAAE,EACf,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,MAAM,EAAE,CAOV;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EAAE,EACf,aAAa,CAAC,EAAE,MAAM,EAAE,GACvB,MAAM,EAAE,CAOV;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EAAE,EACf,KAAK,EAAE,aAAa,GACnB,MAAM,EAAE,CAGV"}