├── .gitignore
├── LICENSE
├── README.md
├── bun.lockb
├── data.json
├── docker-compose.yml
├── package-lock.json
├── package.json
├── pocman.ts
├── tests
├── test-1
│ ├── v1
│ │ ├── Dockerfile
│ │ ├── index.php
│ │ └── readme.txt
│ └── v2
│ │ ├── Dockerfile
│ │ ├── app.py
│ │ ├── readme.txt
│ │ └── requirements.txt
├── test-10
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-11
│ └── v1
│ │ ├── .env
│ │ ├── Dockerfile
│ │ ├── access.log
│ │ └── data.txt
├── test-12
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-13
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-14
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-15
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-16
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-17
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-19
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-2
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-20
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-21
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-22
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-23
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-24
│ └── v1
│ │ ├── Dockerfile
│ │ ├── index.php
│ │ └── user_log.txt
├── test-25
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-26
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-27
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-28
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-29
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.html
├── test-3
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-30
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-31
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-32
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-33
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-34
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-35
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-36
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-37
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-38
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-39
│ └── v1
│ │ ├── Dockerfile
│ │ ├── index.php
│ │ └── ssl.conf
├── test-4
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-40
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-41
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-42
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-44
│ ├── v1
│ │ ├── Dockerfile
│ │ └── index.php
│ └── v2
│ │ ├── Dockerfile
│ │ ├── package.json
│ │ ├── public
│ │ └── index.html
│ │ └── server.js
├── test-45
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-46
│ └── v1
│ │ ├── Controllers
│ │ └── UserController.cs
│ │ ├── Dockerfile
│ │ ├── Models
│ │ └── User.cs
│ │ ├── Program.cs
│ │ ├── Test46.csproj
│ │ ├── Tests
│ │ └── UserControllerTests.cs
│ │ └── wwwroot
│ │ └── index.html
├── test-47
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-48
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-49
│ └── v1
│ │ └── Dockerfile
├── test-5
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-50
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-51
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-52
│ └── v1
│ │ ├── Dockerfile
│ │ ├── index.html
│ │ ├── package.json
│ │ └── server.js
├── test-53
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-54
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-55
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-56
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-6
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-7
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
├── test-8
│ └── v1
│ │ ├── Dockerfile
│ │ └── index.php
└── test-9
│ └── v1
│ ├── Dockerfile
│ ├── index.php
│ └── readme.txt
├── utils
├── checkProfileConsistency.ts
├── findMissingTests.ts
├── findUncoveredCwes.ts
└── types.ts
└── visualizer
├── .editorconfig
├── .eslintrc-auto-import.json
├── .gitattributes
├── .gitignore
├── .prettierrc.json
├── auto-imports.d.ts
├── bun.lockb
├── components.d.ts
├── env.d.ts
├── eslint.config.ts
├── index.html
├── package-lock.json
├── package.json
├── public
└── favicon.ico
├── src
├── App.vue
├── assets
│ ├── base.css
│ ├── logo.svg
│ └── main.css
├── components
│ ├── BarChart.vue
│ ├── ChartControls.vue
│ ├── DashboardPage.vue
│ ├── DataTable.vue
│ ├── HeatmapChart.vue
│ ├── RadarChart.vue
│ ├── ToolCoverageGap.vue
│ ├── data.ts
│ ├── icons
│ │ ├── IconCommunity.vue
│ │ ├── IconDocumentation.vue
│ │ ├── IconEcosystem.vue
│ │ ├── IconSupport.vue
│ │ └── IconTooling.vue
│ └── types.ts
├── main.ts
├── router
│ └── index.ts
├── stores
│ └── counter.ts
├── views
│ └── HomeView.vue
└── vite-env.d.ts
├── tsconfig.json
└── vite.config.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .vscode
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AppSec Detection Framework (ASDF)
2 |
3 | A framework for understanding the capabilities of automated detection methods at identifying classes of application security vulnerabilities.
4 |
5 | ## Table of Contents
6 |
7 | - [Overview](#overview)
8 | - [Requirements](#requirements)
9 | - [Getting Started](#getting-started)
10 | - [Running Tests](#running-tests)
11 | - [Management Interface](#management-interface)
12 | - [Recorded Tests Generator](#recorded-tests-generator)
13 | - [Project Structure](#project-structure)
14 | - [Tests](#tests)
15 | - [Data Management](#data-management)
16 | - [data.json](#datajson)
17 | - [Analysis Utilities](#analysis-utilities)
18 | - [Docker Configuration](#docker-configuration)
19 | - [docker-compose.yml](#docker-composeyml)
20 | - [Dockerfile](#dockerfile)
21 | - [Vulnerable Code](#vulnerable-code)
22 | - [Data Visualization](#data-visualization)
23 | - [Setup](#setup)
24 | - [Features](#features)
25 | - [Linting](#linting)
26 | - [Contributing](#contributing)
27 | - [License](#license)
28 |
29 | ## Overview
30 |
31 | ASDF is designed to evaluate and compare the effectiveness of various security scanners in detecting common web application vulnerabilities. It provides a standardized set of vulnerable applications and a framework for testing security tools against them.
32 |
33 | ## Requirements
34 |
35 | - [Bun](https://bun.sh) - JavaScript runtime and package manager
36 | - [Docker](https://www.docker.com) - Container platform
37 | - [Docker Compose](https://docs.docker.com/compose/) - Multi-container Docker application tool
38 |
39 | ## Getting Started
40 |
41 | ### Running Tests
42 |
43 | To test a new scanner or set of exploits, you'll use Pocman, which orchestrates the proof of concept applications in this repository.
44 |
45 | 1. Install dependencies:
46 | ```sh
47 | bun install
48 | ```
49 |
50 | 2. Run Pocman:
51 | ```sh
52 | ./pocman.ts
53 | ```
54 |
55 | 3. Navigate through test batches:
56 | - Pocman deploys proofs of concept in batches (default: 15 images) to avoid resource constraints
57 | - Enter 'next' in the command prompt to navigate to the next batch
58 | - The index of proof of concepts will be hosted on `localhost:3000`
59 | - Point your scanner to this URL to crawl all available PoCs
60 |
61 | #### Management Interface
62 |
63 | Pocman now includes a web-based management interface that allows you to control the test batches through a browser:
64 |
65 | 1. Access the management interface at `http://localhost:3001` while Pocman is running
66 | 2. Use the control buttons to:
67 | - Navigate to the next batch
68 | - Return to the previous batch
69 | - Stop the current batch
70 | - Start the current batch
71 | - Restart the current batch
72 | 3. View the current batch status
73 | 4. Generate recordedTests output for your scanner
74 |
75 | ##### Recorded Tests Generator
76 |
77 | The management interface now includes a utility to help generate the `recordedTests` output for your scanner:
78 |
79 | 1. Enter your scanner name (e.g., "zap_v2.16.0")
80 | 2. Provide a description of your scanner's configuration in the scan profile field
81 | 3. For each test in the current batch:
82 | - Select which CWEs were detected by checking the boxes in the "Detected CWEs" column
83 | - Select which CWEs were not detected by checking the boxes in the "Undetected CWEs" column
84 | - A CWE can only be in one category at a time (detected or undetected)
85 | 4. Click "Generate Recorded Tests" to create the JSON output
86 | 5. Copy the output and add it to your `data.json` file
87 |
88 | This utility makes it easy to record your scanner's test results in the correct format for the ASDF framework.
89 |
90 | For more information, run:
91 | ```sh
92 | bun install && ./pocman.ts --help
93 | ```
94 |
95 | ## Project Structure
96 |
97 | ### Tests
98 |
99 | The `tests` folder contains all of the definitions for each of the vulnerabilities. The structure of this folder should be:
100 |
101 | ```bash
102 | tests/
103 | ├── test-1/ # The test ID of the vulnerability (increments)
104 | │ └── v1/ # The version of the specific test
105 | │ ├── Dockerfile # The dockerfile for building the test environment
106 | │ └── index.php # The vulnerable code (can be any language)
107 | ├── test-2/
108 | │ └── v1/
109 | │ ├── Dockerfile
110 | │ └── index.js
111 | └── test-3/
112 | └── v1/
113 | ├── Dockerfile
114 | └── index.py
115 | ```
116 |
117 | Each test folder follows the pattern `test-{id}` where `id` is a sequential number. Within each test folder, there can be multiple versions (v1, v2, etc.) of the same vulnerability test.
118 |
119 | ### Data Management
120 |
121 | #### data.json
122 |
123 | This is the file that contains our test data and the OWASP top 10 CWEs. The file has two main sections:
124 |
125 | 1. `vulnerabilities`: An array of OWASP Top 10 2021 categories and their associated CWEs
126 | 2. `recordedTests`: An object where each key is a scanner name and the value contains the scanner's profile and test results
127 |
128 | Example structure:
129 |
130 | ```json
131 | {
132 | "vulnerabilities": [
133 | {
134 | "OWASP": "A01:2021",
135 | "CWEDetails": [
136 | {
137 | "id": 22,
138 | "title": "Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')",
139 | "tests": ["test_1_v1", "test_1_v2"]
140 | }
141 | ],
142 | "group": "Broken Access Control"
143 | }
144 | ],
145 | "recordedTests": {
146 | "scanner_name": {
147 | "scanProfile": "Description of the scanner's capabilities and purpose",
148 | "tests": [
149 | {
150 | "test": "test_1_v1",
151 | "detectedCWEs": [22, 693],
152 | "undetectedCWEs": [23],
153 | "updatedAt": 1740999692
154 | }
155 | ]
156 | }
157 | }
158 | }
159 | ```
160 |
161 | When adding new test results:
162 |
163 | 1. The scanner name should include the version number (e.g., "zap_v2.16.0")
164 | 2. The `scanProfile` should describe the scanner's configuration
165 | 3. Each test result should include:
166 | - `test`: The name of the docker container of the test
167 | - `detectedCWEs`: Array of CWE IDs that were detected
168 | - `undetectedCWEs`: Array of CWE IDs that were not detected
169 | - `updatedAt`: Unix timestamp of when the test occurred
170 |
171 | > [!TIP]
172 | > You can use the Recorded Tests Generator in the management interface to easily create this output in the correct format.
173 |
174 | #### Analysis Utilities
175 |
176 | The framework includes utilities to help analyze the data.json file and identify gaps in test coverage:
177 |
178 | ##### Find Missing Tests
179 |
180 | ```bash
181 | bun run utils/findMissingTests.ts [options]
182 | ```
183 |
184 | This utility analyzes scanner results to identify:
185 | - Missing tests that haven't been run by a scanner
186 | - Missing CWEs that should be detected but aren't
187 | - Incorrect CWE associations (CWEs that are reported but shouldn't be)
188 |
189 | Options:
190 | - `--file `: Path to the data.json file (default: 'data.json')
191 | - `-v, --verbose`: Enable verbose output
192 |
193 | ##### Find Uncovered CWEs
194 |
195 | ```bash
196 | bun run utils/findUncoveredCwes.ts [options]
197 | ```
198 |
199 | This utility identifies CWEs that lack test coverage in the framework:
200 | - CWEs with no associated tests
201 | - CWEs with limited coverage (only one test)
202 |
203 | Options:
204 | - `--file `: Path to the data.json file (default: 'data.json')
205 | - `-v, --verbose`: Enable verbose output
206 |
207 | ##### Check Profile Consistency
208 |
209 | ```bash
210 | bun run utils/checkProfileConsistency.ts
211 | ```
212 |
213 | This utility verifies that the profiles in docker-compose.yml match the CWEs and OWASP categories associated with tests in data.json. It performs case-insensitive matching and identifies:
214 |
215 | - Tests in docker-compose.yml that don't exist in data.json
216 | - CWEs in docker-compose.yml profiles that don't exist in data.json
217 | - OWASP categories in docker-compose.yml profiles that don't exist in data.json
218 | - Tests in data.json that don't exist in docker-compose.yml
219 | - CWEs in data.json that aren't referenced in docker-compose.yml profiles
220 | - OWASP categories in data.json that aren't referenced in docker-compose.yml profiles
221 | - Tests that are missing the "all" profile in docker-compose.yml
222 |
223 | The utility will exit with code 1 if any inconsistencies are found, making it suitable for CI/CD pipelines.
224 |
225 | > [!TIP]
226 | > Use these utilities regularly to identify gaps in test coverage and ensure your scanner results are accurate.
227 |
228 | ### Docker Configuration
229 |
230 | #### docker-compose.yml
231 |
232 | The `docker-compose.yml` file manages the deployment of groups of containers.
233 |
234 | ##### Port Configuration
235 |
236 | Each container should port forward from a local port on the host using an unreserved port (above 1024), following the convention `8 {test ID} {version number}`:
237 | - test 1 v1 would use port `8011`
238 | - test 2 v1 would use port `8021`
239 |
240 | ##### Service Profiles
241 |
242 | The `profiles` should be defined for each service to include:
243 |
244 | - The language the vulnerability was written in (e.g., php, js, python)
245 | - The webserver technology in use (e.g., apache, nginx)
246 | - CWE IDs associated with the vulnerability (e.g., cwe-23)
247 | - The OWASP Top 10 2021 category code (e.g., a01:2021)
248 | - The profile of "all" to ensure these are run by default
249 |
250 | Example entry:
251 |
252 | ```yaml
253 | services:
254 | test_1_v1:
255 | image: test_1_v1:latest
256 | build:
257 | context: tests/test-1/v1/
258 | dockerfile: Dockerfile
259 | ports:
260 | - "8011:80"
261 | profiles:
262 | - a01:2021
263 | - php
264 | - apache
265 | - cwe-23
266 | - cwe-22
267 | - all
268 | ```
269 |
270 | #### Dockerfile
271 |
272 | The `Dockerfile` is responsible for deploying the vulnerable code. It should:
273 |
274 | 1. Set up the appropriate runtime environment
275 | 2. Install necessary dependencies
276 | 3. Copy the vulnerable code into the container
277 | 4. Configure the web server to serve the application
278 |
279 | #### Vulnerable Code
280 |
281 | The vulnerable code (typically named `index.php`, `index.js`, etc.) should:
282 |
283 | - Be brief and easily readable
284 | - Focus solely on demonstrating the vulnerability
285 | - Avoid unnecessary styling or details that don't contribute to the vulnerability
286 | - Be properly commented to explain the vulnerability
287 |
288 | ## Data Visualization
289 |
290 | The `visualizer` directory contains ASDFviz, a Vue-based visualization tool for analyzing the test results.
291 |
292 | ### Setup
293 |
294 | 1. Navigate to the visualizer directory:
295 | ```sh
296 | cd visualizer
297 | ```
298 |
299 | 2. Install dependencies:
300 | ```sh
301 | bun install -D
302 | ```
303 |
304 | 3. Start the development server:
305 | ```sh
306 | bun dev
307 | ```
308 |
309 | 4. Access the visualization at `http://localhost:5173`
310 |
311 | ### Features
312 |
313 | - Coverage gap analysis
314 | - Detection rate comparison
315 | - OWASP category analysis
316 | - CWE-specific analysis
317 | - Export functionality for test results
318 |
319 | ### Linting
320 |
321 | To lint the code with ESLint:
322 | ```sh
323 | bun lint
324 | ```
325 |
326 | ## Contributing
327 |
328 | Contributions are welcome! There are two main ways to contribute to ASDF:
329 |
330 | ### Adding a New Test
331 |
332 | You can identify CWEs that we don't currently have tests for by running `bun run utils/findUncoveredCwes.ts`
333 |
334 | To add a test into the collection:
335 |
336 | 1. Create a new test directory in `tests/` following the naming convention `test-{id}/v1/`
337 | 2. Create a `Dockerfile` that:
338 | - Sets up the appropriate runtime environment
339 | - Installs necessary dependencies
340 | - Copies the vulnerable code
341 | - Configures the web server
342 | 3. Create the vulnerable code file (e.g., `index.php`, `index.js`) that:
343 | - Demonstrates a specific vulnerability
344 | - Is brief and easily readable
345 | - Includes clear comments explaining the vulnerability
346 | 4. Update `docker-compose.yml` to include your test with appropriate:
347 | - Port mapping (following the `8{test_id}{version}` convention)
348 | - Service profiles (language, webserver, CWE IDs, OWASP category)
349 | 5. Add your test to `data.json` under the appropriate OWASP category and CWE
350 | 6. Validate your changes using the analysis utilities:
351 | ```sh
352 | # Ensure profile consistency across data.json and docker-compose.yml
353 | bun run utils/checkProfileConsistency.ts
354 | ```
355 |
356 | ### Adding Scan Results
357 |
358 | 1. Run your security scanner against the test suite using Pocman
359 | 2. Use the Recorded Tests Generator in the management interface (`http://localhost:3001`) to:
360 | - Enter your scanner name and version
361 | - Provide a detailed scan profile
362 | - Record which CWEs were detected/undetected for each test
363 | 3. Add the generated JSON to `data.json` under the `recordedTests` section
364 | 4. Ensure your scanner name includes the version number (e.g., "zap_v2.16.0")
365 | 5. Include a detailed `scanProfile` that describes your scanner's configuration
366 | 6. Validate your scan results:
367 | ```sh
368 | # Check for missing tests in your scan results
369 | bun run utils/findMissingTests.ts
370 | ```
371 |
372 | > [!IMPORTANT]
373 | > Always run the validation utilities before submitting your contribution. They help ensure:
374 | > - All tests are properly documented in data.json
375 | > - CWEs are correctly associated with tests
376 | > - Docker profiles match the documented vulnerabilities
377 | > - No tests or CWEs are missing from your scan results
378 |
379 | For both types of contributions:
380 | 1. Fork the repository
381 | 2. Create a feature branch (`git checkout -b feature/your-contribution`)
382 | 3. Commit your changes (`git commit -m 'Add test/scan results for [description]'`)
383 | 4. Push to the branch (`git push origin feature/your-contribution`)
384 | 5. Open a Pull Request
385 |
386 | ## License
387 |
388 | This project is licensed under the MIT License - see the LICENSE file for details.
389 |
--------------------------------------------------------------------------------
/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cytix-software/AppSec-Detection-Framework/882e5a4cf4eb04cf563644bbf36c126cbeeb639c/bun.lockb
--------------------------------------------------------------------------------
/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | test_1_v1:
3 | image: test_1_v1:latest
4 | build:
5 | context: tests/test-1/v1/
6 | dockerfile: Dockerfile
7 | ports:
8 | - "8011:80"
9 | profiles:
10 | - test-1
11 | - a01:2021
12 | - php
13 | - apache
14 | - cwe-23
15 | - cwe-22
16 | - all
17 | test_1_v2:
18 | image: test_1_v2:latest
19 | build:
20 | context: tests/test-1/v2/
21 | dockerfile: Dockerfile
22 | ports:
23 | - "8012:80"
24 | profiles:
25 | - test-1
26 | - a01:2021
27 | - python
28 | - flask
29 | - cwe-23
30 | - cwe-22
31 | - all
32 | test_2_v1:
33 | image: test_2_v1:latest
34 | build:
35 | context: tests/test-2/v1/
36 | dockerfile: Dockerfile
37 | ports:
38 | - "8021:80"
39 | profiles:
40 | - test-2
41 | - php
42 | - apache
43 | - cwe-78
44 | - a03:2021
45 | - all
46 |
47 | test_3_v1:
48 | image: test_3_v1:latest
49 | build:
50 | context: tests/test-3/v1/
51 | dockerfile: Dockerfile
52 | ports:
53 | - "8031:80"
54 | profiles:
55 | - test-3
56 | - php
57 | - apache
58 | - cwe-352
59 | - a01:2021
60 | - all
61 |
62 | test_4_v1:
63 | image: test_4_v1:latest
64 | build:
65 | context: tests/test-4/v1/
66 | dockerfile: Dockerfile
67 | ports:
68 | - "8041:80"
69 | profiles:
70 | - test-4
71 | - php
72 | - apache
73 | - cwe-80
74 | - a03:2021
75 | - all
76 |
77 | test_5_v1:
78 | image: test_5_v1:latest
79 | build:
80 | context: tests/test-5/v1/
81 | dockerfile: Dockerfile
82 | ports:
83 | - "8051:80"
84 | profiles:
85 | - test-5
86 | - php
87 | - apache
88 | - cwe-83
89 | - a03:2021
90 | - all
91 |
92 | test_6_v1:
93 | image: test_6_v1:latest
94 | build:
95 | context: tests/test-6/v1/
96 | dockerfile: Dockerfile
97 | ports:
98 | - "8061:80"
99 | profiles:
100 | - test-6
101 | - php
102 | - apache
103 | - cwe-434
104 | - a04:2021
105 | - all
106 |
107 | test_7_v1:
108 | image: test_7_v1:latest
109 | build:
110 | context: tests/test-7/v1/
111 | dockerfile: Dockerfile
112 | ports:
113 | - "8071:80"
114 | profiles:
115 | - test-7
116 | - php
117 | - apache
118 | - cwe-502
119 | - a08:2021
120 | - all
121 |
122 | test_8_v1:
123 | image: test_8_v1:latest
124 | build:
125 | context: tests/test-8/v1/
126 | dockerfile: Dockerfile
127 | ports:
128 | - "8081:80"
129 | profiles:
130 | - test-8
131 | - php
132 | - apache
133 | - cwe-1004
134 | - a05:2021
135 | - all
136 |
137 | test_9_v1:
138 | image: test_9_v1:latest
139 | build:
140 | context: tests/test-9/v1/
141 | dockerfile: Dockerfile
142 | ports:
143 | - "8091:80"
144 | profiles:
145 | - test-9
146 | - php
147 | - apache
148 | - cwe-35
149 | - cwe-22
150 | - a01:2021
151 | - all
152 |
153 | test_10_v1:
154 | image: test_10_v1:latest
155 | build:
156 | context: tests/test-10/v1/
157 | dockerfile: Dockerfile
158 | ports:
159 | - "8101:80"
160 | profiles:
161 | - test-10
162 | - php
163 | - apache
164 | - cwe-276
165 | - a01:2021
166 | - all
167 |
168 | test_11_v1:
169 | image: test_11_v1:latest
170 | build:
171 | context: tests/test-11/v1/
172 | dockerfile: Dockerfile
173 | ports:
174 | - "8111:80"
175 | profiles:
176 | - test-11
177 | - php
178 | - apache
179 | - cwe-219
180 | - cwe-552
181 | - cwe-256
182 | - a01:2021
183 | - a04:2021
184 | - all
185 |
186 | test_12_v1:
187 | image: test_12_v1:latest
188 | build:
189 | context: tests/test-12/v1/
190 | dockerfile: Dockerfile
191 | ports:
192 | - "8121:80"
193 | profiles:
194 | - test-12
195 | - php
196 | - apache
197 | - cwe-377
198 | - a01:2021
199 | - all
200 |
201 | test_13_v1:
202 | image: test_13_v1:latest
203 | build:
204 | context: tests/test-13/v1/
205 | dockerfile: Dockerfile
206 | ports:
207 | - "8131:80"
208 | profiles:
209 | - test-13
210 | - php
211 | - apache
212 | - cwe-862
213 | - a01:2021
214 | - all
215 |
216 | test_14_v1:
217 | image: test_14_v1:latest
218 | build:
219 | context: tests/test-14/v1/
220 | dockerfile: Dockerfile
221 | ports:
222 | - "8141:80"
223 | profiles:
224 | - test-14
225 | - php
226 | - apache
227 | - cwe-863
228 | - cwe-287
229 | - cwe-784
230 | - cwe-565
231 | - a01:2021
232 | - a07:2021
233 | - a08:2021
234 | - all
235 |
236 | test_15_v1:
237 | image: test_15_v1:latest
238 | build:
239 | context: tests/test-15/v1/
240 | dockerfile: Dockerfile
241 | ports:
242 | - "8151:80"
243 | profiles:
244 | - test-15
245 | - php
246 | - apache
247 | - cwe-328
248 | - cwe-327
249 | - cwe-759
250 | - cwe-916
251 | - a02:2021
252 | - all
253 |
254 | test_16_v1:
255 | image: test_16_v1:latest
256 | build:
257 | context: tests/test-16/v1/
258 | dockerfile: Dockerfile
259 | ports:
260 | - "8161:80"
261 | profiles:
262 | - test-16
263 | - php
264 | - apache
265 | - a10:2021
266 | - cwe-918
267 | - a03:2021
268 | - cwe-78
269 | - all
270 |
271 | test_17_v1:
272 | image: test_17_v1:latest
273 | build:
274 | context: tests/test-17/v1/
275 | dockerfile: Dockerfile
276 | ports:
277 | - "8171:80"
278 | profiles:
279 | - test-17
280 | - php
281 | - apache
282 | - cwe-760
283 | - cwe-327
284 | - cwe-328
285 | - cwe-916
286 | - cwe-321
287 | - cwe-798
288 | - a02:2021
289 | - a07:2021
290 | - all
291 |
292 | test_19_v1:
293 | image: test_19_v1:latest
294 | build:
295 | context: tests/test-19/v1/
296 | dockerfile: Dockerfile
297 | ports:
298 | - "8191:80"
299 | profiles:
300 | - test-19
301 | - php
302 | - apache
303 | - cwe-501
304 | - cwe-287
305 | - A04:2021
306 | - A07:2021
307 | - all
308 |
309 | test_20_v1:
310 | image: test_20_v1:latest
311 | build:
312 | context: tests/test-20/v1/
313 | dockerfile: Dockerfile
314 | ports:
315 | - "8201:80"
316 | profiles:
317 | - test-20
318 | - php
319 | - apache
320 | - cwe-778
321 | - cwe-799
322 | - cwe-223
323 | - cwe-307
324 | - a09:2021
325 | - a07:2021
326 | - a04:2021
327 | - all
328 |
329 | test_21_v1:
330 | image: test_21_v1:latest
331 | build:
332 | context: tests/test-21/v1/
333 | dockerfile: Dockerfile
334 | ports:
335 | - "8211:80"
336 | profiles:
337 | - test-21
338 | - php
339 | - apache
340 | - cwe-117
341 | - A09:2021
342 | - all
343 |
344 | test_22_v1:
345 | image: test_22_v1:latest
346 | build:
347 | context: tests/test-22/v1/
348 | dockerfile: Dockerfile
349 | ports:
350 | - "8221:80"
351 | profiles:
352 | - test-22
353 | - php
354 | - apache
355 | - cwe-613
356 | - a07:2021
357 | - all
358 |
359 | test_23_v1:
360 | image: test_23_v1:latest
361 | build:
362 | context: tests/test-23/v1/
363 | dockerfile: Dockerfile
364 | ports:
365 | - "8231:80"
366 | profiles:
367 | - test-23
368 | - php
369 | - apache
370 | - cwe-384
371 | - a07:2021
372 | - all
373 |
374 | test_24_v1:
375 | image: test_24_v1:latest
376 | build:
377 | context: tests/test-24/v1/
378 | dockerfile: Dockerfile
379 | ports:
380 | - "8241:80"
381 | profiles:
382 | - test-24
383 | - php
384 | - apache
385 | - cwe-359
386 | - cwe-522
387 | - cwe-532
388 | - a01:2021
389 | - a04:2021
390 | - a09:2021
391 | - all
392 |
393 | test_25_v1:
394 | image: test_25_v1:latest
395 | build:
396 | context: tests/test-25/v1/
397 | dockerfile: Dockerfile
398 | ports:
399 | - "8251:80"
400 | profiles:
401 | - test-25
402 | - php
403 | - apache
404 | - cwe-98
405 | - cwe-706
406 | - cwe-829
407 | - cwe-426
408 | - a01:2021
409 | - a03:2021
410 | - A08:2021
411 | - all
412 |
413 | test_26_v1:
414 | image: test_26_v1:latest
415 | build:
416 | context: tests/test-26/v1/
417 | dockerfile: Dockerfile
418 | ports:
419 | - "8261:80"
420 | profiles:
421 | - test-26
422 | - php
423 | - apache
424 | - cwe-646
425 | - cwe-345
426 | - a04:2021
427 | - a08:2021
428 | - all
429 |
430 | test_27_v1:
431 | image: test_27_v1:latest
432 | build:
433 | context: tests/test-27/v1/
434 | dockerfile: Dockerfile
435 | ports:
436 | - "8271:80"
437 | profiles:
438 | - test-27
439 | - php
440 | - apache
441 | - cwe-353
442 | - cwe-345
443 | - a08:2021
444 | - all
445 |
446 | test_28_v1:
447 | image: test_28_v1:latest
448 | build:
449 | context: tests/test-28/v1/
450 | dockerfile: Dockerfile
451 | ports:
452 | - "8281:80"
453 | profiles:
454 | - test-28
455 | - php
456 | - apache
457 | - cwe-494
458 | - cwe-345
459 | - a08:2021
460 | - all
461 |
462 | test_29_v1:
463 | image: test_29_v1:latest
464 | build:
465 | context: tests/test-29/v1/
466 | dockerfile: Dockerfile
467 | ports:
468 | - "8291:80"
469 | profiles:
470 | - test-29
471 | - php
472 | - apache
473 | - cwe-830
474 | - cwe-829
475 | - a08:2021
476 | - all
477 |
478 | test_30_v1:
479 | image: test_30_v1:latest
480 | build:
481 | context: tests/test-30/v1/
482 | dockerfile: Dockerfile
483 | ports:
484 | - "8301:80"
485 | profiles:
486 | - test-30
487 | - php
488 | - apache
489 | - cwe-915
490 | - cwe-913
491 | - a08:2021
492 | - a01:2021
493 | - all
494 |
495 | test_31_v1:
496 | image: test_31_v1:latest
497 | build:
498 | context: tests/test-31/v1/
499 | dockerfile: Dockerfile
500 | ports:
501 | - "8311:80"
502 | profiles:
503 | - test-31
504 | - php
505 | - apache
506 | - cwe-940
507 | - cwe-346
508 | - cwe-352
509 | - a07:2021
510 | - a01:2021
511 | - all
512 |
513 | test_32_v1:
514 | image: test_32_v1:latest
515 | build:
516 | context: tests/test-32/v1/
517 | dockerfile: Dockerfile
518 | ports:
519 | - "8321:80"
520 | profiles:
521 | - test-32
522 | - php
523 | - apache
524 | - cwe-640
525 | - cwe-257
526 | - cwe-256
527 | - cwe-798
528 | - cwe-307
529 | - a07:2021
530 | - a04:2021
531 | - all
532 |
533 | test_33_v1:
534 | image: test_33_v1:latest
535 | build:
536 | context: tests/test-33/v1/
537 | dockerfile: Dockerfile
538 | ports:
539 | - "8331:80"
540 | profiles:
541 | - test-33
542 | - apache
543 | - php
544 | - cwe-620
545 | - cwe-306
546 | - cwe-352
547 | - cwe-598
548 | - a07:2021
549 | - a04:2021
550 | - a01:2021
551 | - all
552 |
553 | test_34_v1:
554 | image: test_34_v1:latest
555 | build:
556 | context: tests/test-34/v1/
557 | dockerfile: Dockerfile
558 | ports:
559 | - "8341:80"
560 | profiles:
561 | - test-34
562 | - apache
563 | - php
564 | - cwe-521
565 | - a07:2021
566 | - all
567 |
568 | test_35_v1:
569 | image: test_35_v1:latest
570 | build:
571 | context: tests/test-35/v1/
572 | dockerfile: Dockerfile
573 | ports:
574 | - "8351:80"
575 | profiles:
576 | - test-35
577 | - apache
578 | - php
579 | - cwe-302
580 | - cwe-807
581 | - cwe-287
582 | - cwe-784
583 | - cwe-565
584 | - a07:2021
585 | - a04:2021
586 | - a08:2021
587 | - all
588 |
589 | test_36_v1:
590 | image: test_36_v1:latest
591 | build:
592 | context: tests/test-36/v1/
593 | dockerfile: Dockerfile
594 | ports:
595 | - "8361:80"
596 | profiles:
597 | - test-36
598 | - apache
599 | - php
600 | - cwe-297
601 | - cwe-295
602 | - a07:2021
603 | - all
604 |
605 | test_37_v1:
606 | image: test_37_v1:latest
607 | build:
608 | context: tests/test-37/v1/
609 | dockerfile: Dockerfile
610 | ports:
611 | - "8371:80"
612 | profiles:
613 | - test-37
614 | - apache
615 | - php
616 | - cwe-294
617 | - cwe-798
618 | - a07:2021
619 | - all
620 |
621 | test_38_v1:
622 | image: test_38_v1:latest
623 | build:
624 | context: tests/test-38/v1/
625 | dockerfile: Dockerfile
626 | ports:
627 | - "8381:80"
628 | profiles:
629 | - test-38
630 | - apache
631 | - php
632 | - cwe-290
633 | - cwe-287
634 | - cwe-602
635 | - a04:2021
636 | - a07:2021
637 | - all
638 |
639 | test_39_v1:
640 | image: test_39_v1:latest
641 | build:
642 | context: tests/test-39/v1/
643 | dockerfile: Dockerfile
644 | ports:
645 | - "8391:443"
646 | profiles:
647 | - test-39
648 | - apache
649 | - php
650 | - cwe-614
651 | - a05:2021
652 | - all
653 |
654 | test_40_v1:
655 | image: test_40_v1:latest
656 | build:
657 | context: tests/test-40/v1/
658 | dockerfile: Dockerfile
659 | ports:
660 | - "8401:80"
661 | profiles:
662 | - test-40
663 | - apache
664 | - php
665 | - cwe-776
666 | - a01:2021
667 | - cwe-610
668 | - cwe-611
669 | - a03:2021
670 | - a05:2021
671 | - all
672 |
673 | test_41_v1:
674 | image: test_41_v1:latest
675 | build:
676 | context: tests/test-41/v1/
677 | dockerfile: Dockerfile
678 | ports:
679 | - "8411:80"
680 | profiles:
681 | - test-41
682 | - apache
683 | - php
684 | - cwe-315
685 | - a05:2021
686 | - all
687 |
688 | test_42_v1:
689 | image: test_42_v1:latest
690 | build:
691 | context: tests/test-42/v1/
692 | dockerfile: Dockerfile
693 | ports:
694 | - "8421:80"
695 | profiles:
696 | - test-42
697 | - apache
698 | - php
699 | - cwe-526
700 | - cwe-312
701 | - a05:2021
702 | - a04:2021
703 | - all
704 |
705 | test_44_v1:
706 | image: test_44_v1:latest
707 | build:
708 | context: tests/test-44/v1/
709 | dockerfile: Dockerfile
710 | ports:
711 | - "8441:80"
712 | profiles:
713 | - test-44
714 | - apache
715 | - php
716 | - cwe-1104
717 | - cwe-1035
718 | - cwe-79
719 | - a06:2021
720 | - a03:2021
721 | - all
722 |
723 | test_44_v2:
724 | image: test_44_v2:latest
725 | build:
726 | context: tests/test-44/v2/
727 | dockerfile: Dockerfile
728 | ports:
729 | - "8442:80"
730 | profiles:
731 | - test-44
732 | - node
733 | - express
734 | - cwe-1104
735 | - cwe-79
736 | - a06:2021
737 | - a03:2021
738 | - all
739 |
740 | test_45_v1:
741 | image: test_45_v1:latest
742 | build:
743 | context: tests/test-45/v1/
744 | dockerfile: Dockerfile
745 | ports:
746 | - "8451:80"
747 | profiles:
748 | - test-45
749 | - php
750 | - apache
751 | - cwe-1275
752 | - cwe-1004
753 | - a01:2021
754 | - a05:2021
755 | - all
756 |
757 | test_46_v1:
758 | image: test_46_v1:latest
759 | build:
760 | context: tests/test-46/v1/
761 | dockerfile: Dockerfile
762 | ports:
763 | - "8461:80"
764 | profiles:
765 | - test-46
766 | - dotnet
767 | - aspnet
768 | - cwe-1174
769 | - cwe-1173
770 | - a05:2021
771 | - a04:2021
772 | - all
773 |
774 | test_47_v1:
775 | image: test_47_v1:latest
776 | build:
777 | context: tests/test-47/v1/
778 | dockerfile: Dockerfile
779 | ports:
780 | - "8471:80"
781 | profiles:
782 | - test-47
783 | - apache
784 | - php
785 | - cwe-840
786 | - a04:2021
787 | - all
788 |
789 | test_48_v1:
790 | image: test_48_v1:latest
791 | build:
792 | context: tests/test-48/v1/
793 | dockerfile: Dockerfile
794 | ports:
795 | - "8481:80"
796 | profiles:
797 | - test-48
798 | - apache
799 | - php
800 | - cwe-1021
801 | - a04:2021
802 | - cwe-451
803 | - all
804 |
805 | test_49_v1:
806 | image: test_49_v1:latest
807 | build:
808 | context: tests/test-49/v1/
809 | dockerfile: Dockerfile
810 | ports:
811 | - "8491:80"
812 | profiles:
813 | - test-49
814 | - apache
815 | - cwe-756
816 | - a05:2021
817 | - all
818 |
819 | test_50_v1:
820 | image: test_50_v1:latest
821 | build:
822 | context: tests/test-50/v1/
823 | dockerfile: Dockerfile
824 | ports:
825 | - "8501:80"
826 | profiles:
827 | - test-50
828 | - apache
829 | - php
830 | - cwe-942
831 | - a05:2021
832 | - all
833 |
834 | test_51_v1:
835 | image: test_51_v1:latest
836 | build:
837 | context: tests/test-51/v1/
838 | dockerfile: Dockerfile
839 | ports:
840 | - "8511:80"
841 | profiles:
842 | - test-51
843 | - apache
844 | - php
845 | - cwe-651
846 | - a01:2021
847 | - all
848 |
849 | test_52_v1:
850 | image: test_52_v1:latest
851 | build:
852 | context: tests/test-52/v1/
853 | dockerfile: Dockerfile
854 | ports:
855 | - "8521:80"
856 | profiles:
857 | - test-52
858 | - node
859 | - cwe-523
860 | - a02:2021
861 | - all
862 |
863 | test_53_v1:
864 | image: test_53_v1:latest
865 | build:
866 | context: tests/test-53/v1/
867 | dockerfile: Dockerfile
868 | ports:
869 | - "8531:80"
870 | profiles:
871 | - test-53
872 | - apache
873 | - php
874 | - cwe-525
875 | - a04:2021
876 | - all
877 |
878 | test_54_v1:
879 | image: test_54_v1:latest
880 | build:
881 | context: tests/test-54/v1/
882 | dockerfile: Dockerfile
883 | ports:
884 | - "8541:80"
885 | profiles:
886 | - test-54
887 | - apache
888 | - php
889 | - cwe-601
890 | - a01:2021
891 | - all
892 |
893 | test_55_v1:
894 | image: test_55_v1:latest
895 | build:
896 | context: tests/test-55/v1/
897 | dockerfile: Dockerfile
898 | ports:
899 | - "8551:80"
900 | profiles:
901 | - test-55
902 | - apache
903 | - php
904 | - cwe-538
905 | - a01:2021
906 | - all
907 |
908 | test_56_v1:
909 | image: test_56_v1:latest
910 | build:
911 | context: ./tests/test-56/v1
912 | ports:
913 | - "8561:80"
914 | profiles:
915 | - test-56
916 | - apache
917 | - php
918 | - cwe-284
919 | - a01:2021
920 | - all
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "appsec-detection-framework",
3 | "version": "1.0.0",
4 | "description": "Framework for testing and comparing application security scanners",
5 | "module": "index.ts",
6 | "type": "module",
7 | "scripts": {
8 | "find-uncovered": "bun run utils/findUncoveredCwes.ts",
9 | "find-missing": "bun run utils/findMissingTests.ts",
10 | "check-profiles": "bun run utils/checkProfileConsistency.ts"
11 | },
12 | "dependencies": {
13 | "@koa/router": "^13.1.0",
14 | "@types/koa-bodyparser": "^4.3.12",
15 | "@types/lodash": "^4.17.15",
16 | "@types/minimist": "^1.2.5",
17 | "common-tags": "^1.8.2",
18 | "js-yaml": "^4.1.0",
19 | "koa": "^2.15.4",
20 | "koa-bodyparser": "^4.4.1",
21 | "lodash": "^4.17.21",
22 | "minimist": "^1.2.8",
23 | "yaml": "^2.7.0",
24 | "commander": "^11.1.0"
25 | },
26 | "devDependencies": {
27 | "@types/bun": "^1.0.0",
28 | "@types/js-yaml": "^4.0.9"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/tests/test-1/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php readme.txt ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-1/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-1/v1/readme.txt:
--------------------------------------------------------------------------------
1 | Hello, world!
--------------------------------------------------------------------------------
/tests/test-1/v2/Dockerfile:
--------------------------------------------------------------------------------
1 | # Use Python 3.11 slim image as base
2 | FROM python:3.11-slim
3 |
4 | # Set working directory
5 | WORKDIR /app
6 |
7 | # Copy requirements first to leverage Docker cache
8 | COPY requirements.txt .
9 |
10 | # Install dependencies
11 | RUN pip install --no-cache-dir -r requirements.txt
12 |
13 | # Copy the application code
14 | COPY app.py readme.txt .
15 |
16 | # Create a non-root user for security
17 | RUN useradd -m appuser && chown -R appuser:appuser /app
18 | USER appuser
19 |
20 | # Expose the port the app runs on
21 | EXPOSE 80
22 |
23 | # Command to run the application
24 | CMD ["python", "app.py"]
--------------------------------------------------------------------------------
/tests/test-1/v2/app.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request, render_template_string
2 | import os
3 |
4 | app = Flask(__name__)
5 |
6 | # HTML template with the form
7 | HTML_TEMPLATE = '''
8 |
12 | '''
13 |
14 | @app.route('/', methods=['GET', 'POST'])
15 | def index():
16 | if request.method == 'POST':
17 | filename = "./"
18 | filename += request.form['input']
19 | try:
20 | with open(filename, 'r') as f:
21 | output = f.read()
22 | return HTML_TEMPLATE + output
23 | except Exception as e:
24 | return HTML_TEMPLATE + str(e)
25 | return HTML_TEMPLATE
26 |
27 | if __name__ == '__main__':
28 | app.run(host='0.0.0.0', port=80)
--------------------------------------------------------------------------------
/tests/test-1/v2/readme.txt:
--------------------------------------------------------------------------------
1 | Hello, world!
--------------------------------------------------------------------------------
/tests/test-1/v2/requirements.txt:
--------------------------------------------------------------------------------
1 | flask==3.0.2
--------------------------------------------------------------------------------
/tests/test-10/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | RUN chmod -R 777 /var/www/html
5 | EXPOSE 80
6 |
7 |
--------------------------------------------------------------------------------
/tests/test-10/v1/index.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/tests/test-11/v1/.env:
--------------------------------------------------------------------------------
1 | # Mock .env File
2 |
3 | # User Information (Plaintext)
4 | USER_1_USERNAME=Desmond
5 | USER_1_PASSWORD=bearsuperiority
6 | USER_2_USERNAME=Ryan
7 | USER_2_PASSWORD=iliketrains
8 | USER_3_USERNAME=Mr.Muffin
9 | USER_3_PASSWORD=ItsMuffinTime!
10 |
11 | # Admin User (Plaintext)
12 | ADMIN_USERNAME=Mr.T
13 | ADMIN_PASSWORD=meow
14 |
15 | # API Keys (Plaintext)
16 | GOOGLE_API_KEY=AIzaSyD1m0cK3y-FakeKey12345
17 | AWS_SECRET_KEY=AKIAIOSFODNN7EXAMPLE
18 | STRIPE_SECRET_KEY=sk_test_4eC39HqLyjWDarjtT1zdp7dc
19 |
20 | DEBUG=true
21 |
22 | # Database Credentials (Plaintext)
23 | DB_HOST=localhost
24 | DB_PORT=3306
25 | DB_USER=root
26 | DB_PASSWORD= password123
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/test-11/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY access.log data.txt .env ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-11/v1/access.log:
--------------------------------------------------------------------------------
1 | 127.0.0.1 - - [21/Jan/2025:10:15:23 +0000] "GET / HTTP/1.1" 200 1127
2 | 192.168.1.100 - - [21/Jan/2025:10:15:00 +0000] "POST /index.php HTTP/1.1" 200 384
3 | 192.168.1.104 - - [21/Jan/2025:10:17:00 +0000] "GET /data.txt HTTP/1.1" 200 512
4 | 192.168.1.105 - - [21/Jan/2025:10:17:00 +0000] "GET /access.log HTTP/1.1" 200 512
--------------------------------------------------------------------------------
/tests/test-11/v1/data.txt:
--------------------------------------------------------------------------------
1 | OO O o o o... ______________________ _________________
2 | O ____ | | | |
3 | ][_n_i_| ( ooo___ | | | |
4 | (__________|_[______]_|____________________|_|_______________|
5 | 0--0--0 0 0 0 0 0 0 0
--------------------------------------------------------------------------------
/tests/test-12/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-12/v1/index.php:
--------------------------------------------------------------------------------
1 | ";
7 | chmod($temp_filename, 0644); // Insecure Permissions.
8 |
9 | // Write Data to file.
10 | $file = fopen($temp_filename, 'wb');
11 | if ($file) {
12 | $data = "Sensitive data flavour.";
13 | fwrite($file, $data);
14 | fclose($file);
15 |
16 | // Reads file.
17 | echo "File contents: ";
18 | include($temp_filename);
19 | echo " ";
20 |
21 | // Delete file.
22 | if (file_exists($temp_filename)) {
23 | unlink($temp_filename);
24 | echo "Temporary file deleted.";
25 | } else {
26 | echo "Temporary file does not exist when attempting to delete.\n";
27 | }
28 | } else {
29 | echo "Failed to open temporary file for writing.\n";
30 | }
31 | } else {
32 | echo "Failed to create temporary file.\n";
33 | }
34 | ?>
35 |
--------------------------------------------------------------------------------
/tests/test-13/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
5 |
--------------------------------------------------------------------------------
/tests/test-13/v1/index.php:
--------------------------------------------------------------------------------
1 | ['name' => 'Desmond Bear', 'position' => 'Moon Bear', 'email' => 'Desmond.Bear@example.com'],
5 | 'DougalF' => ['name' => 'Dougal Flop', 'position' => 'Flop Guy', 'email' => 'Dougal.Flop@example.com']
6 | ];
7 |
8 | // Function to fetch employee data
9 | function runEmployeeQuery($employees, $name){
10 | // Vulnerability: No authorization check before returning data
11 | if (isset($employees[$name])) {
12 | return $employees[$name];
13 | }
14 | return null;
15 | }
16 |
17 | // Check for employee in GET request.
18 | if (isset($_GET['EmployeeName'])) {
19 | $employeeName = $_GET['EmployeeName'];
20 | $employeeData = runEmployeeQuery($employees, $employeeName);
21 |
22 | // Display the employee data.
23 | if ($employeeData) {
24 | echo "Employee Information: ";
25 | echo "Name: " . $employeeData['name'] . "
";
26 | echo "Position: " . $employeeData['position'] . "
";
27 | echo "Email: " . $employeeData['email'] . "
";
28 | } else {
29 | echo "No employee found with the name $employeeName.
";
30 | }
31 | } else {
32 | echo "Please provide an employee name to query.
";
33 | }
34 | ?>
35 |
36 |
41 |
--------------------------------------------------------------------------------
/tests/test-14/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-14/v1/index.php:
--------------------------------------------------------------------------------
1 |
32 |
--------------------------------------------------------------------------------
/tests/test-15/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-15/v1/index.php:
--------------------------------------------------------------------------------
1 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Vulnerable Login System
34 |
35 |
36 | Login
37 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/tests/test-16/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-16/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-17/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-17/v1/index.php:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Vulnerable Login System
33 |
34 |
35 | Login
36 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/tests/test-19/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-19/v1/index.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 | Improper Authentication
17 |
18 |
19 |
20 | Logged in as:
21 |
22 | Please provide your username:
23 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/tests/test-2/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-2/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-20/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-20/v1/index.php:
--------------------------------------------------------------------------------
1 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Login Page
33 |
34 |
35 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/test-21/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-21/v1/index.php:
--------------------------------------------------------------------------------
1 |
2 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | Test 21
27 |
28 |
29 | Enter a Value
30 |
35 |
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/test-22/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-22/v1/index.php:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 | Test 22
14 |
15 |
16 | Test 22
17 | Die potato!
18 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/test-23/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-23/v1/index.php:
--------------------------------------------------------------------------------
1 | Logged in as: " . htmlspecialchars($_SESSION["user"]) . "
";
8 | }
9 | ?>
10 |
11 |
12 |
13 |
14 | Vulnerable Login - Session Fixation
15 |
16 |
17 | Login
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/tests/test-24/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-24/v1/index.php:
--------------------------------------------------------------------------------
1 |
2 | "password123",
11 | "user1" => "mypassword",
12 | "user2" => "securepass"
13 | ];
14 |
15 | $records = [
16 | "admin" => "10 Downing Street, London",
17 | "user1" => "The white house, Washington DC",
18 | "user2" => "Kremlin, Moscow"
19 | ];
20 |
21 | if ($_SERVER["REQUEST_METHOD"] == "POST") {
22 | $username = $_POST["username"];
23 | $password = $_POST["password"];
24 |
25 | if (isset($users[$username]) && $users[$username] === $password) {
26 | file_put_contents($logFile, "User: $username | Password: $password | Record Data: $records[$username] | IP: " . $_SERVER["REMOTE_ADDR"] . "\n", FILE_APPEND);
27 | echo "Welcome, $username! ";
28 | } else {
29 | echo "Invalid credentials
";
30 | }
31 | }
32 | ?>
33 |
34 |
35 |
36 |
37 | Test 24
38 |
39 |
40 | Login
41 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/tests/test-24/v1/user_log.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cytix-software/AppSec-Detection-Framework/882e5a4cf4eb04cf563644bbf36c126cbeeb639c/tests/test-24/v1/user_log.txt
--------------------------------------------------------------------------------
/tests/test-25/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-25/v1/index.php:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/tests/test-26/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | RUN mkdir -p /var/www/html/uploads && \
5 | chown -R www-data:www-data /var/www/html/uploads && \
6 | chmod -R 755 /var/www/html/uploads
7 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-26/v1/index.php:
--------------------------------------------------------------------------------
1 | $fileName";
14 | } else {
15 | echo "Failed to upload file.";
16 | }
17 | } else {
18 | echo "Invalid file type.";
19 | }
20 | }
21 | ?>
22 |
23 |
24 |
25 |
26 | Vulnerable File Upload
27 |
28 |
29 | Upload a File
30 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/tests/test-27/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-27/v1/index.php:
--------------------------------------------------------------------------------
1 | Received Message:";
7 | echo "" . htmlspecialchars($message) . "
";
8 | }
9 | ?>
10 |
11 |
12 |
13 |
14 | Test 27
15 |
16 |
17 | Send a Message
18 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/tests/test-28/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-28/v1/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Vulnerable JavaScript Loading
5 |
6 |
7 |
8 |
9 | jQuery Library Test
10 |
11 | Test jQuery
12 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/tests/test-29/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.html ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-29/v1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Weather Widget
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/test-3/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-3/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-30/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-30/v1/index.php:
--------------------------------------------------------------------------------
1 | $value) {
10 | $this->$key = $value; // Mass assignment vulnerability
11 | }
12 | }
13 | }
14 |
15 | if ($_SERVER['REQUEST_METHOD'] === 'POST') {
16 | $userData = $_POST; // Accepts user input directly
17 | $user = new User($userData); // Creates a user object with dynamic attributes
18 |
19 | echo "User Created: ";
20 | echo "Username: " . htmlspecialchars($user->username) . " ";
21 | echo "Email: " . htmlspecialchars($user->email) . " ";
22 | echo "Admin Status: " . ($user->isAdmin ? "Yes" : "No") . " ";
23 | }
24 | ?>
25 |
26 |
27 |
28 |
29 | Vulnerable Mass Assignment Demo
30 |
31 |
32 | Create User
33 |
39 |
40 |
--------------------------------------------------------------------------------
/tests/test-31/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-31/v1/index.php:
--------------------------------------------------------------------------------
1 | "Alice",
7 | 2 => "Bob",
8 | 3 => "Charlie"
9 | ];
10 | }
11 |
12 | function destroyUserData($userID) {
13 | if (isset($_SESSION['users'][$userID])) {
14 | unset($_SESSION['users'][$userID]);
15 | echo "User with ID $userID has been deleted.
";
16 | } else {
17 | echo "No user found with ID $userID.
";
18 | }
19 | }
20 |
21 | // Handle request
22 | if (isset($_GET['userID'])) {
23 | $userID = intval($_GET['userID']);
24 | destroyUserData($userID);
25 | }
26 | ?>
27 |
28 |
29 |
30 |
31 |
32 |
33 | User Deletion
34 |
35 |
36 | Delete User
37 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/tests/test-32/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-32/v1/index.php:
--------------------------------------------------------------------------------
1 | [
4 | "email" => "desmond@themoon.com",
5 | "password" => "password123", // Insecure: password stored in plain text
6 | "security_question" => "What is your favorite color?",
7 | "security_answer" => "blue" // Weak answer (easily guessed or socially discoverable)
8 | ]
9 | ];
10 |
11 | if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['recover'])) {
12 | $username = isset($_POST['username']) ? trim($_POST['username']) : '';
13 | $email = isset($_POST['email']) ? trim($_POST['email']) : '';
14 | $security_answer = isset($_POST['security_answer']) ? strtolower(trim($_POST['security_answer'])) : '';
15 |
16 | if (isset($users[$username])) {
17 | $user = $users[$username];
18 | if ($user['email'] === $email && strtolower($user['security_answer']) === $security_answer) {
19 | echo "Password recovery successful! Your password is: " . htmlspecialchars($user['password']) . "
";
20 | } else {
21 | echo "Error: Invalid email or security answer provided.
";
22 | }
23 | } else {
24 | echo "Error: User not found.
";
25 | }
26 | }
27 | ?>
28 |
29 |
30 |
31 |
32 |
33 | Password Recovery
34 |
35 |
36 | Password Recovery
37 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/tests/test-33/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-33/v1/index.php:
--------------------------------------------------------------------------------
1 | Password for user " . htmlspecialchars($user) . " has been changed to " . htmlspecialchars($pass) . ".";
10 | } else {
11 | echo "Passwords do not match! ";
12 | }
13 | }
14 | ?>
15 |
16 |
17 |
18 |
19 |
20 |
21 | Password Change
22 |
23 |
24 | Change Password Form
25 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/test-34/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-34/v1/index.php:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 | Test 34
15 |
16 |
17 | Register New User
18 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/tests/test-35/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-35/v1/index.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Test 35
5 |
6 |
7 | Welcome, authenticated user!";
10 | echo "Super secret data: I AM A STEGOSAURUS!
";
11 | } else {
12 | echo "Access Denied! ";
13 | echo "You are not authorized to view this page.
";
14 | }
15 | ?>
16 |
17 |
18 |
--------------------------------------------------------------------------------
/tests/test-36/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-36/v1/index.php:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/tests/test-37/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-37/v1/index.php:
--------------------------------------------------------------------------------
1 |
19 |
23 |
26 |
--------------------------------------------------------------------------------
/tests/test-38/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-38/v1/index.php:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/test-39/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | # Enable SSL module
4 | RUN a2enmod ssl
5 |
6 | # Create directory for SSL certificates
7 | RUN mkdir -p /etc/apache2/ssl
8 |
9 | # Generate self-signed certificate
10 | RUN openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
11 | -keyout /etc/apache2/ssl/server.key \
12 | -out /etc/apache2/ssl/server.crt \
13 | -subj "/C=US/ST=State/L=City/O=Organization/CN=localhost"
14 |
15 | # Copy SSL configuration
16 | COPY ssl.conf /etc/apache2/sites-available/default-ssl.conf
17 | RUN a2ensite default-ssl
18 |
19 | WORKDIR /var/www/html
20 | COPY index.php ./
21 |
22 | # Expose HTTPS port
23 | EXPOSE 443
--------------------------------------------------------------------------------
/tests/test-39/v1/index.php:
--------------------------------------------------------------------------------
1 | true, // Protects against JavaScript access (but still vulnerable)
8 | "samesite" => "Strict" // Helps prevent CSRF attacks
9 | ]);
10 |
11 | ?>
12 |
13 |
14 |
15 |
16 | Test 39
17 |
18 |
19 |
--------------------------------------------------------------------------------
/tests/test-39/v1/ssl.conf:
--------------------------------------------------------------------------------
1 |
2 | ServerAdmin webmaster@localhost
3 | DocumentRoot /var/www/html
4 |
5 | ErrorLog ${APACHE_LOG_DIR}/error.log
6 | CustomLog ${APACHE_LOG_DIR}/access.log combined
7 |
8 | SSLEngine on
9 | SSLCertificateFile /etc/apache2/ssl/server.crt
10 | SSLCertificateKeyFile /etc/apache2/ssl/server.key
11 |
12 |
13 | SSLOptions +StdEnvVars
14 |
15 |
16 | SSLOptions +StdEnvVars
17 |
18 |
--------------------------------------------------------------------------------
/tests/test-4/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-4/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-40/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-40/v1/index.php:
--------------------------------------------------------------------------------
1 | children() as $child) {
15 | $result[$child->getName()] = (string)$child;
16 | }
17 |
18 | // Display the processed data
19 | echo 'Processed XML Data ';
20 | echo '';
21 | print_r($result);
22 | echo ' ';
23 |
24 | // Also display the raw XML for debugging
25 | echo 'Raw XML ';
26 | echo '';
27 | echo htmlspecialchars($xml->asXML());
28 | echo ' ';
29 | } else {
30 | echo 'Error: Failed to parse XML file.
';
31 | $errors = libxml_get_errors();
32 | foreach ($errors as $error) {
33 | echo 'XML Error: ' . $error->message . '
';
34 | }
35 | libxml_clear_errors();
36 | }
37 | }
38 | ?>
39 |
40 |
41 |
42 |
43 |
44 | XXE Vulnerability Example
45 |
46 |
47 | Upload an XML file to demonstrate XXE vulnerability
48 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/tests/test-41/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-41/v1/index.php:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | Test 41
22 |
23 |
24 |
--------------------------------------------------------------------------------
/tests/test-42/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-42/v1/index.php:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 | Test 42
16 |
17 |
18 | Stored Environment Variable:
19 |
20 |
21 |
--------------------------------------------------------------------------------
/tests/test-44/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-44/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 | Test 44
9 |
10 |
11 |
12 |
16 |
17 |
18 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/tests/test-44/v2/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18-alpine
2 | WORKDIR /app
3 | COPY package.json ./
4 | RUN npm install
5 | COPY . .
6 | EXPOSE 80
7 | CMD ["node", "server.js"]
--------------------------------------------------------------------------------
/tests/test-44/v2/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "test-44-v2",
3 | "version": "1.0.0",
4 | "description": "Test 44 v2 - DOM XSS with AngularJS 1.2.32",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "node server.js"
8 | },
9 | "dependencies": {
10 | "express": "^4.18.2",
11 | "angular": "1.2.32"
12 | }
13 | }
--------------------------------------------------------------------------------
/tests/test-44/v2/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | DOM XSS Test
5 |
6 |
7 |
8 |
9 |
10 |
Search
11 |
12 |
13 |
14 |
27 |
28 |
--------------------------------------------------------------------------------
/tests/test-44/v2/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const app = express();
4 | const port = 80;
5 |
6 | // Serve static files
7 | app.use(express.static(path.join(__dirname, 'public')));
8 |
9 | // API endpoint that returns user input (vulnerable to XSS)
10 | app.get('/api/search', (req, res) => {
11 | const query = req.query.q || '';
12 | // Intentionally not sanitizing the input to demonstrate the vulnerability
13 | res.json({ results: query });
14 | });
15 |
16 | app.listen(port, () => {
17 | console.log(`Test 44 v2 server running on port ${port}`);
18 | });
--------------------------------------------------------------------------------
/tests/test-45/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:7.4-apache
2 | COPY index.php /var/www/html/
--------------------------------------------------------------------------------
/tests/test-45/v1/index.php:
--------------------------------------------------------------------------------
1 | time() + 3600,
4 | 'path' => '/',
5 | 'secure' => false,
6 | 'httponly' => false
7 | ]);
8 | ?>
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tests/test-46/v1/Controllers/UserController.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Mvc;
2 | using Test46.Models;
3 |
4 | namespace Test46.Controllers
5 | {
6 | [ApiController]
7 | [Route("api/[controller]")]
8 | public class UserController : ControllerBase
9 | {
10 | private static List _users = new();
11 |
12 | [HttpPost("register")]
13 | public IActionResult Register(User user)
14 | {
15 | // No manual validation - relying on automatic model validation
16 | // which is disabled in Program.cs
17 | _users.Add(user);
18 | return Ok();
19 | }
20 |
21 | [HttpGet]
22 | public IActionResult GetUsers()
23 | {
24 | return Ok(_users);
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/tests/test-46/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM mcr.microsoft.com/dotnet/sdk:7.0 AS build
2 | WORKDIR /app
3 | COPY *.csproj ./
4 | RUN dotnet restore
5 | COPY . .
6 | RUN dotnet publish -c Release -o out
7 |
8 | FROM mcr.microsoft.com/dotnet/aspnet:7.0
9 | WORKDIR /app
10 | COPY --from=build /app/out .
11 | EXPOSE 80
12 | ENTRYPOINT ["dotnet", "Test46.dll"]
--------------------------------------------------------------------------------
/tests/test-46/v1/Models/User.cs:
--------------------------------------------------------------------------------
1 | using System.ComponentModel.DataAnnotations;
2 |
3 | namespace Test46.Models
4 | {
5 | public class User
6 | {
7 | [Required]
8 | [MinLength(3)]
9 | public string Username { get; set; }
10 |
11 | [Required]
12 | [EmailAddress]
13 | public string Email { get; set; }
14 |
15 | [Required]
16 | [MinLength(8)]
17 | public string Password { get; set; }
18 |
19 | [Required]
20 | [Range(0, 150)]
21 | public int Age { get; set; }
22 | }
23 | }
--------------------------------------------------------------------------------
/tests/test-46/v1/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Builder;
2 | using Microsoft.AspNetCore.Hosting;
3 | using Microsoft.Extensions.DependencyInjection;
4 | using Microsoft.Extensions.Hosting;
5 | using Microsoft.AspNetCore.Mvc;
6 |
7 | namespace Test46
8 | {
9 | public class Program
10 | {
11 | public static void Main(string[] args)
12 | {
13 | var builder = WebApplication.CreateBuilder(args);
14 |
15 | // Add services to the container.
16 | builder.Services.AddControllers()
17 | .ConfigureApiBehaviorOptions(options =>
18 | {
19 | // Disable automatic model validation
20 | options.SuppressModelStateInvalidFilter = true;
21 | });
22 |
23 | var app = builder.Build();
24 |
25 | // Configure the HTTP request pipeline.
26 | if (app.Environment.IsDevelopment())
27 | {
28 | app.UseDeveloperExceptionPage();
29 | }
30 |
31 | app.UseDefaultFiles();
32 | app.UseStaticFiles();
33 | app.UseHttpsRedirection();
34 | app.UseAuthorization();
35 | app.MapControllers();
36 |
37 | app.Run();
38 | }
39 | }
40 | }
--------------------------------------------------------------------------------
/tests/test-46/v1/Test46.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/test-46/v1/Tests/UserControllerTests.cs:
--------------------------------------------------------------------------------
1 | using System.Net;
2 | using System.Net.Http;
3 | using System.Text;
4 | using System.Text.Json;
5 | using Microsoft.AspNetCore.Mvc.Testing;
6 | using Test46.Models;
7 | using Xunit;
8 |
9 | namespace Test46.Tests
10 | {
11 | public class UserControllerTests : IClassFixture>
12 | {
13 | private readonly WebApplicationFactory _factory;
14 | private readonly HttpClient _client;
15 |
16 | public UserControllerTests(WebApplicationFactory factory)
17 | {
18 | _factory = factory;
19 | _client = _factory.CreateClient();
20 | }
21 |
22 | [Fact]
23 | public async Task Register_WithInvalidModel_StillSucceeds()
24 | {
25 | // Arrange
26 | var invalidUser = new User
27 | {
28 | // Missing required fields
29 | Username = "", // Empty username
30 | Email = "not-an-email", // Invalid email format
31 | Password = "123" // Too short password
32 | };
33 |
34 | var content = new StringContent(
35 | JsonSerializer.Serialize(invalidUser),
36 | Encoding.UTF8,
37 | "application/json");
38 |
39 | // Act
40 | var response = await _client.PostAsync("/api/user/register", content);
41 |
42 | // Assert
43 | Assert.Equal(HttpStatusCode.OK, response.StatusCode);
44 |
45 | // Verify the invalid user was actually added
46 | var getResponse = await _client.GetAsync("/api/user");
47 | var users = await JsonSerializer.DeserializeAsync>(
48 | await getResponse.Content.ReadAsStreamAsync());
49 |
50 | Assert.Contains(users, u => u.Email == invalidUser.Email);
51 | }
52 | }
53 | }
--------------------------------------------------------------------------------
/tests/test-46/v1/wwwroot/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | CWE-1174 Demo - Model Validation Bypass
7 |
90 |
91 |
92 |
93 |
User Registration Form (CWE-1174 Demo)
94 |
95 |
96 |
Expected Validation Rules:
97 |
98 | Username: Required, minimum 3 characters
99 | Email: Required, must be valid email format
100 | Password: Required, minimum 8 characters
101 | Age: Required, between 0 and 150
102 |
103 |
Note: Due to disabled model validation (CWE-1174), these rules are not enforced!
104 |
105 |
106 |
125 |
126 |
127 |
128 |
129 |
Registered Users
130 |
131 |
132 |
133 | Username
134 | Email
135 | Password
136 | Age
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
220 |
221 |
--------------------------------------------------------------------------------
/tests/test-47/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-47/v1/index.php:
--------------------------------------------------------------------------------
1 | true, 'total' => $total]);
15 | exit;
16 | }
17 | ?>
18 |
19 |
20 |
21 |
22 |
Premium Widget
23 |
Price: $100.00
24 |
25 | Quantity:
26 |
27 |
28 |
Total: $100.00
29 |
Add to Cart
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
Shopping Cart
38 |
39 |
40 |
Cart Total: $0.00
41 |
Place Order
42 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/tests/test-48/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
--------------------------------------------------------------------------------
/tests/test-48/v1/index.php:
--------------------------------------------------------------------------------
1 |
14 |
15 |
16 |
17 | Secure Banking
18 |
19 |
20 | Secure Banking
21 | Please enter your transfer details below:
22 |
23 |
38 |
39 |
--------------------------------------------------------------------------------
/tests/test-49/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | # Expose port 80
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-5/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-5/v1/index.php:
--------------------------------------------------------------------------------
1 | 1
2 |
3 | ";
7 | }
8 | ?>
--------------------------------------------------------------------------------
/tests/test-50/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | # Copy the vulnerable application
4 | COPY index.php /var/www/html/
5 |
6 | # Expose port 80
7 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-50/v1/index.php:
--------------------------------------------------------------------------------
1 | '12345',
14 | 'email' => 'user@example.com',
15 | 'role' => 'admin'
16 | ];
17 |
18 | // Return the sensitive data as JSON
19 | header('Content-Type: application/json');
20 | echo json_encode($sensitiveData);
21 | ?>
--------------------------------------------------------------------------------
/tests/test-51/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | # Copy the vulnerable application
4 | COPY index.php /var/www/html/
5 |
6 | # Expose port 80
7 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-51/v1/index.php:
--------------------------------------------------------------------------------
1 |
11 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | XML;
82 |
83 | // Output the WSDL file
84 | echo $wsdl;
85 | ?>
--------------------------------------------------------------------------------
/tests/test-52/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18-alpine
2 |
3 | WORKDIR /app
4 |
5 | COPY package*.json ./
6 | RUN npm install
7 |
8 | COPY . .
9 |
10 | EXPOSE 80
11 |
12 | CMD ["node", "server.js"]
--------------------------------------------------------------------------------
/tests/test-52/v1/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CWE-523 Test
5 |
6 |
7 | Login Form (Vulnerable to CWE-523)
8 |
13 |
14 |
15 |
36 |
37 |
--------------------------------------------------------------------------------
/tests/test-52/v1/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cwe-523-test",
3 | "version": "1.0.0",
4 | "description": "Test for CWE-523: Unprotected Transport of Credentials",
5 | "main": "server.js",
6 | "dependencies": {
7 | "express": "^4.18.2"
8 | }
9 | }
--------------------------------------------------------------------------------
/tests/test-52/v1/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const path = require('path');
3 | const app = express();
4 |
5 | app.use(express.json());
6 | app.use(express.static(path.join(__dirname)));
7 |
8 | // Vulnerable to CWE-523: Unprotected Transport of Credentials
9 | // This server sends credentials over HTTP instead of HTTPS
10 | app.post('/login', (req, res) => {
11 | const { username, password } = req.body;
12 |
13 | // Simulate authentication
14 | if (username === 'admin' && password === 'password123') {
15 | res.json({
16 | status: 'success',
17 | message: 'Login successful',
18 | // Sensitive data sent over HTTP
19 | userData: {
20 | id: 1,
21 | role: 'admin',
22 | apiKey: 'FAKE_API_KEY_1234567890',
23 | sessionToken: 'FAKE_SESSION_TOKEN_1234567890'
24 | }
25 | });
26 | } else {
27 | res.status(401).json({
28 | status: 'error',
29 | message: 'Invalid credentials'
30 | });
31 | }
32 | });
33 |
34 | app.listen(80, () => {
35 | console.log('Server running on http://localhost:80');
36 | });
--------------------------------------------------------------------------------
/tests/test-53/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | COPY . /var/www/html/
4 |
5 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-53/v1/index.php:
--------------------------------------------------------------------------------
1 | 1,
10 | 'username' => 'admin',
11 | 'role' => 'administrator',
12 | 'apiKey' => 'FAKE_API_KEY_1234567890'
13 | ];
14 | }
15 |
16 | // Set cache control headers to cache everything
17 | header('Cache-Control: public, max-age=31536000'); // Cache for 1 year
18 | header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + 31536000)); // Expires in 1 year
19 | header('Pragma: public'); // Explicitly allow caching
20 | header('Content-Type: application/json');
21 |
22 | // Return sensitive user data that will be cached by the browser
23 | echo json_encode([
24 | 'status' => 'success',
25 | 'user' => $_SESSION['user'],
26 | 'sensitiveData' => [
27 | 'accountNumber' => '1234567890',
28 | 'balance' => 10000.00,
29 | 'lastTransaction' => '2024-03-20T10:00:00Z',
30 | 'creditCard' => [
31 | 'number' => '4111111111111111',
32 | 'expiry' => '12/25',
33 | 'cvv' => '123'
34 | ]
35 | ]
36 | ]);
37 | ?>
--------------------------------------------------------------------------------
/tests/test-54/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | COPY . /var/www/html/
4 |
5 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-54/v1/index.php:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 | Open Redirect Test
15 |
16 |
17 | Open Redirect Vulnerability Test
18 | Enter any URL to redirect to:
19 |
23 | Example: Try redirecting to https://example.com
24 |
25 |
26 |
--------------------------------------------------------------------------------
/tests/test-55/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | COPY . /var/www/html/
4 |
5 | # Ensure the debug log file is writable
6 | RUN touch /var/www/html/debug.log && \
7 | chmod 666 /var/www/html/debug.log
8 |
9 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-55/v1/index.php:
--------------------------------------------------------------------------------
1 | 1,
8 | 'username' => 'admin',
9 | 'apiKey' => 'FAKE_API_KEY_1234567890',
10 | 'creditCard' => [
11 | 'number' => '4111111111111111',
12 | 'expiry' => '12/25',
13 | 'cvv' => '123'
14 | ]
15 | ];
16 |
17 | // Add random transaction data
18 | $userData['transaction'] = [
19 | 'id' => 'TX' . rand(100000, 999999),
20 | 'amount' => rand(10, 1000),
21 | 'timestamp' => date('Y-m-d H:i:s'),
22 | 'status' => 'completed'
23 | ];
24 |
25 | // Vulnerable: Store sensitive data in a publicly accessible log file
26 | $logEntry = json_encode($userData, JSON_PRETTY_PRINT) . "\n---\n";
27 | file_put_contents('debug.log', $logEntry, FILE_APPEND);
28 |
29 | // Read the last few entries to display
30 | $logContent = file_exists('debug.log') ? file_get_contents('debug.log') : '';
31 | $entries = array_filter(explode('---', $logContent));
32 | $lastEntries = array_slice($entries, -5); // Show last 5 entries
33 | ?>
34 |
35 |
36 |
37 | CWE-538 Test
38 |
41 |
42 |
43 | Sensitive Data Storage Test
44 | New transaction data has been automatically stored in the log file.
45 |
46 | Recent Log Entries:
47 |
48 |
49 |
50 |
51 | Note: This test stores sensitive data in a publicly accessible file at debug.log
52 |
53 |
--------------------------------------------------------------------------------
/tests/test-56/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 |
3 | # Copy application files
4 | COPY . /var/www/html/
5 |
6 | # Expose port 80
7 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-56/v1/index.php:
--------------------------------------------------------------------------------
1 | 'user' // Regular user role
11 | ];
12 | }
13 |
14 | // Vulnerable function: No proper access control check
15 | function getAdminData() {
16 | // Missing proper role check
17 | return [
18 | 'admin_users' => [
19 | ['username' => 'admin1', 'email' => 'admin1@example.com'],
20 | ['username' => 'admin2', 'email' => 'admin2@example.com']
21 | ],
22 | 'system_settings' => [
23 | 'maintenance_mode' => false,
24 | 'debug_mode' => true
25 | ]
26 | ];
27 | }
28 |
29 | // Handle admin data request
30 | if (isset($_GET['action']) && $_GET['action'] === 'get_admin_data') {
31 | header('Content-Type: application/json');
32 | echo json_encode(getAdminData());
33 | exit;
34 | }
35 | ?>
36 |
37 |
38 |
39 |
40 | CWE-284
41 |
45 |
46 |
47 | CWE-284: Improper Access Control
48 | Current role:
49 | Get Admin Data
50 |
51 |
52 |
62 |
63 |
--------------------------------------------------------------------------------
/tests/test-6/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-6/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 |
--------------------------------------------------------------------------------
/tests/test-7/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-7/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 | inject)){
15 | eval($this->inject);
16 | }
17 | }
18 | }
19 | $output=unserialize($input);
20 | echo $output[0];
21 | }
22 | ?>
--------------------------------------------------------------------------------
/tests/test-8/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-8/v1/index.php:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/tests/test-9/v1/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM php:8.2-apache
2 | WORKDIR /var/www/html
3 | COPY index.php ./
4 | EXPOSE 80
--------------------------------------------------------------------------------
/tests/test-9/v1/index.php:
--------------------------------------------------------------------------------
1 |
5 |
6 | ";
13 |
14 | if (is_file($filename)) {
15 | $handle = fopen($filename, 'r');
16 | $output = fread($handle, filesize($filename));
17 | fclose($handle);
18 | echo nl2br(htmlspecialchars($output));
19 | } else {
20 | echo "File not found or invalid file.";
21 | }
22 | }
23 | ?>
--------------------------------------------------------------------------------
/tests/test-9/v1/readme.txt:
--------------------------------------------------------------------------------
1 | Hello world!
--------------------------------------------------------------------------------
/utils/checkProfileConsistency.ts:
--------------------------------------------------------------------------------
1 | import { Data } from './types';
2 | import fs from 'fs';
3 | import yaml from 'js-yaml';
4 |
5 | interface DockerService {
6 | profiles?: string[];
7 | }
8 |
9 | interface DockerCompose {
10 | services: Record;
11 | }
12 |
13 | function loadData(): Data {
14 | const data = fs.readFileSync('data.json', 'utf8');
15 | return JSON.parse(data);
16 | }
17 |
18 | function loadDockerCompose(): DockerCompose {
19 | const dockerCompose = fs.readFileSync('docker-compose.yml', 'utf8');
20 | return yaml.load(dockerCompose) as DockerCompose;
21 | }
22 |
23 | function extractCweFromProfile(profile: string): number | null {
24 | const match = profile.match(/^cwe-(\d+)$/i);
25 | return match ? parseInt(match[1], 10) : null;
26 | }
27 |
28 | function extractOwaspFromProfile(profile: string): string | null {
29 | const match = profile.match(/^a\d{2}:\d{4}$/i);
30 | return match ? match[0].toLowerCase() : null;
31 | }
32 |
33 | function findCweInData(cweId: number, data: Data): boolean {
34 | return data.vulnerabilities.some(vuln =>
35 | vuln.CWEDetails.some(cwe => cwe.id === cweId)
36 | );
37 | }
38 |
39 | function findTestInData(testName: string, data: Data): boolean {
40 | return data.vulnerabilities.some(vuln =>
41 | vuln.CWEDetails.some(cwe => cwe.tests.includes(testName))
42 | );
43 | }
44 |
45 | function getOwaspForTest(testName: string, data: Data): string[] {
46 | const owaspCategories = new Set();
47 |
48 | for (const vuln of data.vulnerabilities) {
49 | for (const cwe of vuln.CWEDetails) {
50 | if (cwe.tests.includes(testName)) {
51 | owaspCategories.add(vuln.OWASP.toLowerCase());
52 | }
53 | }
54 | }
55 |
56 | return Array.from(owaspCategories);
57 | }
58 |
59 | function getCwesForTest(testName: string, data: Data): number[] {
60 | const cweIds = new Set();
61 |
62 | for (const vuln of data.vulnerabilities) {
63 | for (const cwe of vuln.CWEDetails) {
64 | if (cwe.tests.includes(testName)) {
65 | cweIds.add(cwe.id);
66 | }
67 | }
68 | }
69 |
70 | return Array.from(cweIds);
71 | }
72 |
73 | function main() {
74 | const data = loadData();
75 | const dockerCompose = loadDockerCompose();
76 |
77 | const inconsistencies: string[] = [];
78 |
79 | // Check each service in docker-compose.yml
80 | for (const [serviceName, service] of Object.entries(dockerCompose.services)) {
81 | if (!service.profiles) continue;
82 |
83 | // Check if test exists in data.json
84 | if (!findTestInData(serviceName, data)) {
85 | inconsistencies.push(`Test "${serviceName}" exists in docker-compose.yml but not in data.json`);
86 | continue;
87 | }
88 |
89 | // Check if test has the "all" profile
90 | if (!service.profiles.some(p => p.toLowerCase() === 'all')) {
91 | inconsistencies.push(`Test "${serviceName}" is missing the "all" profile in docker-compose.yml`);
92 | }
93 |
94 | // Get expected CWEs and OWASP categories from data.json
95 | const expectedCwes = getCwesForTest(serviceName, data);
96 | const expectedOwasp = getOwaspForTest(serviceName, data);
97 |
98 | // Check CWE profiles
99 | const cweProfiles = service.profiles
100 | .filter(profile => profile.toLowerCase().startsWith('cwe-'))
101 | .map(profile => extractCweFromProfile(profile))
102 | .filter((cweId): cweId is number => cweId !== null);
103 |
104 | // Check for missing CWEs in docker-compose.yml
105 | for (const cweId of expectedCwes) {
106 | const cweProfile = `cwe-${cweId}`;
107 | if (!service.profiles?.some(p => p.toLowerCase() === cweProfile.toLowerCase())) {
108 | inconsistencies.push(`CWE-${cweId} is referenced in data.json for "${serviceName}" but not in docker-compose.yml profiles`);
109 | }
110 | }
111 |
112 | // Check for extra CWEs in docker-compose.yml
113 | for (const cweId of cweProfiles) {
114 | if (!expectedCwes.includes(cweId)) {
115 | inconsistencies.push(`CWE-${cweId} is referenced in docker-compose.yml for "${serviceName}" but not found in data.json`);
116 | }
117 | }
118 |
119 | // Check OWASP profiles
120 | const owaspProfiles = service.profiles
121 | .filter(profile => profile.toLowerCase().match(/^a\d{2}:\d{4}$/))
122 | .map(profile => extractOwaspFromProfile(profile))
123 | .filter((owasp): owasp is string => owasp !== null);
124 |
125 | // Check for missing OWASP categories in docker-compose.yml
126 | for (const owasp of expectedOwasp) {
127 | if (!owaspProfiles.includes(owasp)) {
128 | inconsistencies.push(`OWASP category "${owasp}" is referenced in data.json for "${serviceName}" but not in docker-compose.yml profiles`);
129 | }
130 | }
131 |
132 | // Check for extra OWASP categories in docker-compose.yml
133 | for (const owasp of owaspProfiles) {
134 | if (!expectedOwasp.includes(owasp)) {
135 | inconsistencies.push(`OWASP category "${owasp}" is referenced in docker-compose.yml for "${serviceName}" but not found in data.json`);
136 | }
137 | }
138 | }
139 |
140 | // Check each test in data.json
141 | for (const vuln of data.vulnerabilities) {
142 | for (const cwe of vuln.CWEDetails) {
143 | for (const test of cwe.tests) {
144 | const service = dockerCompose.services[test];
145 | if (!service) {
146 | inconsistencies.push(`Test "${test}" exists in data.json but not in docker-compose.yml`);
147 | }
148 | }
149 | }
150 | }
151 |
152 | if (inconsistencies.length === 0) {
153 | console.log('✅ All profiles and vulnerabilities are consistent between docker-compose.yml and data.json');
154 | } else {
155 | console.log('❌ Found inconsistencies between docker-compose.yml and data.json:');
156 | inconsistencies.forEach(msg => console.log(` - ${msg}`));
157 | process.exit(1);
158 | }
159 | }
160 |
161 | if (require.main === module) {
162 | main();
163 | }
--------------------------------------------------------------------------------
/utils/findMissingTests.ts:
--------------------------------------------------------------------------------
1 | import { program } from 'commander';
2 | import { Data } from './types';
3 |
4 | interface CWEDetail {
5 | id: number;
6 | title: string;
7 | tests: string[];
8 | }
9 |
10 | interface Vulnerability {
11 | OWASP: string;
12 | CWEDetails: CWEDetail[];
13 | }
14 |
15 | interface TestResult {
16 | test: string;
17 | detectedCWEs: number[];
18 | undetectedCWEs: number[];
19 | }
20 |
21 | interface ScannerResult {
22 | scanProfile: string;
23 | tests: TestResult[];
24 | }
25 |
26 | interface TestCWEMap {
27 | [key: string]: Set;
28 | }
29 |
30 | interface IncorrectCWEs {
31 | detected: Set;
32 | undetected: Set;
33 | }
34 |
35 | interface IncorrectCWEMap {
36 | [key: string]: IncorrectCWEs;
37 | }
38 |
39 | export async function loadData(): Promise {
40 | try {
41 | const file = Bun.file('data.json');
42 | return await file.json();
43 | } catch (error) {
44 | console.error(`Error loading data file: ${error}`);
45 | process.exit(1);
46 | }
47 | }
48 |
49 | function getAllTestsAndCWEs(data: Data): [Set, TestCWEMap] {
50 | const allTests = new Set();
51 | const testCWEs: TestCWEMap = {};
52 |
53 | // Get tests and CWEs from vulnerabilities section
54 | for (const vuln of data.vulnerabilities) {
55 | for (const cweDetail of vuln.CWEDetails) {
56 | const cweId = cweDetail.id.toString();
57 | for (const test of cweDetail.tests) {
58 | allTests.add(test);
59 | if (!testCWEs[test]) {
60 | testCWEs[test] = new Set();
61 | }
62 | testCWEs[test].add(cweId);
63 | }
64 | }
65 | }
66 |
67 | return [allTests, testCWEs];
68 | }
69 |
70 | function analyzeScannerResults(
71 | scannerName: string,
72 | scanner: ScannerResult,
73 | allTests: Set,
74 | testCWEs: TestCWEMap
75 | ): [Set, TestCWEMap, IncorrectCWEMap] {
76 | const missingTests = new Set();
77 | const missingCWEs: TestCWEMap = {};
78 | const incorrectCWEs: IncorrectCWEMap = {};
79 |
80 | // Get tests that the scanner has run
81 | const scannerTests = new Set(scanner.tests.map(test => test.test));
82 |
83 | // Find missing tests
84 | for (const test of allTests) {
85 | if (!scannerTests.has(test)) {
86 | missingTests.add(test);
87 | }
88 | }
89 |
90 | // Find missing and incorrect CWEs for each test
91 | for (const test of scanner.tests) {
92 | const testName = test.test;
93 | if (!testName) continue;
94 |
95 | // Get CWEs that the scanner detected and undetected
96 | const detectedCWEs = new Set(test.detectedCWEs.map(cwe => cwe.toString()));
97 | const undetectedCWEs = new Set(test.undetectedCWEs.map(cwe => cwe.toString()));
98 | const scannerCWEs = new Set([...detectedCWEs, ...undetectedCWEs]);
99 |
100 | // Get expected CWEs for this test
101 | const expectedCWEs = testCWEs[testName] || new Set();
102 |
103 | // Find missing CWEs (expected but not in scanner results)
104 | const missing = new Set([...expectedCWEs].filter(cwe => !scannerCWEs.has(cwe)));
105 | if (missing.size > 0) {
106 | missingCWEs[testName] = missing;
107 | }
108 |
109 | // Find incorrect CWEs (in scanner results but not expected)
110 | const incorrectDetected = new Set([...detectedCWEs].filter(cwe => !expectedCWEs.has(cwe)));
111 | const incorrectUndetected = new Set([...undetectedCWEs].filter(cwe => !expectedCWEs.has(cwe)));
112 |
113 | if (incorrectDetected.size > 0 || incorrectUndetected.size > 0) {
114 | incorrectCWEs[testName] = {
115 | detected: incorrectDetected,
116 | undetected: incorrectUndetected
117 | };
118 | }
119 | }
120 |
121 | return [missingTests, missingCWEs, incorrectCWEs];
122 | }
123 |
124 | function printResults(
125 | scannerName: string,
126 | missingTests: Set,
127 | missingCWEs: TestCWEMap,
128 | incorrectCWEs: IncorrectCWEMap,
129 | verbose: boolean = false,
130 | simplified: boolean = false
131 | ): void {
132 | if (simplified) {
133 | console.log(`\n=== ${scannerName} ===`);
134 |
135 | // Print missing tests count
136 | console.log(`Missing Tests: ${missingTests.size}`);
137 | if (missingTests.size > 0) {
138 | [...missingTests].sort().forEach(test => {
139 | console.log(` - ${test}`);
140 | });
141 | }
142 |
143 | // Print missing CWEs count
144 | const totalMissingCWEs = Object.values(missingCWEs)
145 | .reduce((sum, cwes) => sum + cwes.size, 0);
146 | console.log(`\nMissing CWEs: ${totalMissingCWEs}`);
147 |
148 | // Print incorrect CWEs count
149 | const totalIncorrectCWEs = Object.values(incorrectCWEs)
150 | .reduce((sum, details) => sum + details.detected.size + details.undetected.size, 0);
151 | console.log(`Incorrect CWEs: ${totalIncorrectCWEs}`);
152 |
153 | return;
154 | }
155 |
156 | console.log(`\n=== Analysis for ${scannerName} ===`);
157 |
158 | if (missingTests.size > 0) {
159 | console.log(`\nMissing Tests (${missingTests.size}):`);
160 | [...missingTests].sort().forEach(test => {
161 | console.log(` - ${test}`);
162 | });
163 | } else {
164 | console.log('\nNo missing tests!');
165 | }
166 |
167 | if (Object.keys(missingCWEs).length > 0) {
168 | const totalMissing = Object.values(missingCWEs)
169 | .reduce((sum, cwes) => sum + cwes.size, 0);
170 | console.log(`\nMissing CWEs (${totalMissing} total):`);
171 | Object.entries(missingCWEs).sort().forEach(([test, cwes]) => {
172 | console.log(`\n ${test}:`);
173 | [...cwes].sort().forEach(cwe => {
174 | console.log(` - CWE-${cwe}`);
175 | });
176 | });
177 | } else {
178 | console.log('\nNo missing CWEs!');
179 | }
180 |
181 | if (Object.keys(incorrectCWEs).length > 0) {
182 | const totalIncorrect = Object.values(incorrectCWEs)
183 | .reduce((sum, details) => sum + details.detected.size + details.undetected.size, 0);
184 | console.log(`\nIncorrect CWE Associations (${totalIncorrect} total):`);
185 | Object.entries(incorrectCWEs).sort().forEach(([test, details]) => {
186 | if (details.detected.size > 0 || details.undetected.size > 0) {
187 | console.log(`\n ${test}:`);
188 | if (details.detected.size > 0) {
189 | console.log(' Incorrectly Detected:');
190 | [...details.detected].sort().forEach(cwe => {
191 | console.log(` - CWE-${cwe}`);
192 | });
193 | }
194 | if (details.undetected.size > 0) {
195 | console.log(' Incorrectly Undetected:');
196 | [...details.undetected].sort().forEach(cwe => {
197 | console.log(` - CWE-${cwe}`);
198 | });
199 | }
200 | }
201 | });
202 | } else {
203 | console.log('\nNo incorrect CWE associations!');
204 | }
205 | }
206 |
207 | async function main(): Promise {
208 | program
209 | .option('--file ', 'Path to the data.json file', 'data.json')
210 | .option('-v, --verbose', 'Enable verbose output')
211 | .option('-s, --simplified', 'Enable simplified output')
212 | .parse(process.argv);
213 |
214 | const options = program.opts();
215 |
216 | // Load data
217 | const data = await loadData();
218 |
219 | // Get all tests and their CWEs
220 | const [allTests, testCWEs] = getAllTestsAndCWEs(data);
221 |
222 | // Analyze each scanner
223 | Object.entries(data.recordedTests).forEach(([scannerName, scanner]) => {
224 | const [missingTests, missingCWEs, incorrectCWEs] = analyzeScannerResults(
225 | scannerName,
226 | scanner,
227 | allTests,
228 | testCWEs
229 | );
230 | printResults(scannerName, missingTests, missingCWEs, incorrectCWEs, options.verbose, options.simplified);
231 | });
232 | }
233 |
234 | if (import.meta.main) {
235 | main();
236 | }
--------------------------------------------------------------------------------
/utils/findUncoveredCwes.ts:
--------------------------------------------------------------------------------
1 | import { program } from 'commander';
2 | import { loadData } from './findMissingTests';
3 | import { Data, CweDetails, Vulnerability } from './types';
4 |
5 | function getAllCwes(data: Data): Map {
6 | const cweMap = new Map();
7 |
8 | for (const vuln of data.vulnerabilities) {
9 | for (const cwe of vuln.CWEDetails) {
10 | // Skip CWEs that are OWASP Top Ten categories
11 | if (!cwe.title.includes('OWASP Top Ten')) {
12 | cweMap.set(cwe.id, cwe.title);
13 | }
14 | }
15 | }
16 |
17 | return cweMap;
18 | }
19 |
20 | function findUncoveredCwes(data: Data, verbose = false, simplified = false): void {
21 | const cweMap = getAllCwes(data);
22 |
23 | // Get all CWEs that have tests
24 | const cwesWithTests = new Set();
25 | for (const vuln of data.vulnerabilities) {
26 | for (const cwe of vuln.CWEDetails) {
27 | // Skip OWASP Top Ten categories when counting tests
28 | if (!cwe.title.includes('OWASP Top Ten') && cwe.tests.length > 0) {
29 | cwesWithTests.add(cwe.id);
30 | }
31 | }
32 | }
33 |
34 | // Find CWEs without tests
35 | const uncoveredCwes = new Set();
36 | for (const [cweId] of cweMap) {
37 | if (!cwesWithTests.has(cweId)) {
38 | uncoveredCwes.add(cweId);
39 | }
40 | }
41 |
42 | if (simplified) {
43 | console.log('\nCWEs without tests:');
44 | console.log('----------------------------------------');
45 | for (const cwe of Array.from(uncoveredCwes).sort((a, b) => a - b)) {
46 | console.log(`${cwe}: ${cweMap.get(cwe)}`);
47 | }
48 | return;
49 | }
50 |
51 | if (verbose) {
52 | console.log('----------------------------------------');
53 | console.log('Note: CWEs with titles containing "OWASP Top Ten" are excluded as these are category references rather than specific CWEs.');
54 | console.log('----------------------------------------');
55 | console.log('\nAnalyzing CWEs without tests');
56 | console.log('----------------------------------------');
57 | console.log(`Total CWEs (excluding OWASP Top Ten categories): ${cweMap.size}`);
58 | console.log(`CWEs with tests: ${cwesWithTests.size}`);
59 | console.log(`CWEs without tests: ${uncoveredCwes.size}`);
60 | console.log('\nCWEs without tests by OWASP Category:');
61 | console.log('----------------------------------------');
62 |
63 | // Group uncovered CWEs by OWASP category
64 | const cwesByCategory = new Map>();
65 | const coveredCwesByCategory = new Map();
66 | const totalCwesByCategory = new Map();
67 |
68 | // Initialize counts for all OWASP categories
69 | for (const vuln of data.vulnerabilities) {
70 | coveredCwesByCategory.set(vuln.OWASP, 0);
71 | totalCwesByCategory.set(vuln.OWASP, 0);
72 | }
73 |
74 | // Count total and covered CWEs for each category
75 | for (const vuln of data.vulnerabilities) {
76 | for (const cwe of vuln.CWEDetails) {
77 | if (!cwe.title.includes('OWASP Top Ten')) {
78 | totalCwesByCategory.set(
79 | vuln.OWASP,
80 | (totalCwesByCategory.get(vuln.OWASP) || 0) + 1
81 | );
82 | if (cwe.tests.length > 0) {
83 | coveredCwesByCategory.set(
84 | vuln.OWASP,
85 | (coveredCwesByCategory.get(vuln.OWASP) || 0) + 1
86 | );
87 | }
88 | }
89 | }
90 | }
91 |
92 | for (const cwe of Array.from(uncoveredCwes).sort((a, b) => a - b)) {
93 | // Find which vulnerabilities this CWE is associated with
94 | for (const vuln of data.vulnerabilities) {
95 | for (const cweDetail of vuln.CWEDetails) {
96 | if (cweDetail.id === cwe) {
97 | if (!cwesByCategory.has(vuln.OWASP)) {
98 | cwesByCategory.set(vuln.OWASP, []);
99 | }
100 | cwesByCategory.get(vuln.OWASP)?.push({
101 | id: cwe,
102 | title: cweMap.get(cwe) || ''
103 | });
104 | }
105 | }
106 | }
107 | }
108 |
109 | // Find categories with complete coverage
110 | const completeCategories = Array.from(totalCwesByCategory.entries())
111 | .filter(([category, total]) => {
112 | const covered = coveredCwesByCategory.get(category) || 0;
113 | return total > 0 && covered === total;
114 | })
115 | .map(([category]) => category)
116 | .sort();
117 |
118 | if (completeCategories.length > 0) {
119 | console.log('\nOWASP Categories with Complete Coverage:');
120 | console.log('----------------------------------------');
121 | for (const category of completeCategories) {
122 | const total = totalCwesByCategory.get(category) || 0;
123 | console.log(`${category} (${total} CWEs covered)`);
124 | }
125 | }
126 |
127 | // Print CWEs grouped by OWASP category
128 | console.log('\nOWASP Categories with Missing Coverage:');
129 | console.log('----------------------------------------');
130 | for (const [category, cwes] of Array.from(cwesByCategory.entries()).sort()) {
131 | const coveredCount = coveredCwesByCategory.get(category) || 0;
132 | const totalCount = totalCwesByCategory.get(category) || 0;
133 | console.log(`\n${category} (${coveredCount}/${totalCount} covered):`);
134 | console.log(' Missing tests for:');
135 | for (const cwe of cwes.sort((a, b) => a.id - b.id)) {
136 | console.log(` - CWE-${cwe.id}: ${cwe.title}`);
137 | }
138 | }
139 | } else {
140 | console.log(`\nCWEs without tests: ${uncoveredCwes.size}`);
141 | console.log('----------------------------------------');
142 | for (const cwe of Array.from(uncoveredCwes).sort((a, b) => a - b)) {
143 | console.log(`CWE-${cwe}: ${cweMap.get(cwe)}`);
144 | }
145 | }
146 | }
147 |
148 | async function main() {
149 | const args = process.argv.slice(2);
150 | const verbose = args.includes('-v') || args.includes('--verbose');
151 | const simplified = args.includes('-s') || args.includes('--simplified');
152 |
153 | const data = await loadData();
154 | findUncoveredCwes(data, verbose, simplified);
155 | }
156 |
157 | if (require.main === module) {
158 | main().catch(error => {
159 | console.error('Error:', error);
160 | process.exit(1);
161 | });
162 | }
--------------------------------------------------------------------------------
/utils/types.ts:
--------------------------------------------------------------------------------
1 | export interface CweDetails {
2 | id: number;
3 | title: string;
4 | tests: string[];
5 | }
6 |
7 | export interface Vulnerability {
8 | OWASP: string;
9 | CWEDetails: CweDetails[];
10 | group: string;
11 | }
12 |
13 | export interface Data {
14 | vulnerabilities: Vulnerability[];
15 | recordedTests: Record;
23 | }>;
24 | }
--------------------------------------------------------------------------------
/visualizer/.editorconfig:
--------------------------------------------------------------------------------
1 | [*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
2 | charset = utf-8
3 | indent_size = 2
4 | indent_style = space
5 | insert_final_newline = true
6 | trim_trailing_whitespace = true
7 |
8 | end_of_line = lf
9 | max_line_length = 100
10 |
--------------------------------------------------------------------------------
/visualizer/.eslintrc-auto-import.json:
--------------------------------------------------------------------------------
1 | {
2 | "globals": {
3 | "Component": true,
4 | "ComponentPublicInstance": true,
5 | "ComputedRef": true,
6 | "DirectiveBinding": true,
7 | "EffectScope": true,
8 | "ExtractDefaultPropTypes": true,
9 | "ExtractPropTypes": true,
10 | "ExtractPublicPropTypes": true,
11 | "InjectionKey": true,
12 | "MaybeRef": true,
13 | "MaybeRefOrGetter": true,
14 | "PropType": true,
15 | "Ref": true,
16 | "VNode": true,
17 | "WritableComputedRef": true,
18 | "computed": true,
19 | "createApp": true,
20 | "customRef": true,
21 | "defineAsyncComponent": true,
22 | "defineComponent": true,
23 | "effectScope": true,
24 | "getCurrentInstance": true,
25 | "getCurrentScope": true,
26 | "h": true,
27 | "inject": true,
28 | "isProxy": true,
29 | "isReactive": true,
30 | "isReadonly": true,
31 | "isRef": true,
32 | "markRaw": true,
33 | "nextTick": true,
34 | "onActivated": true,
35 | "onBeforeMount": true,
36 | "onBeforeRouteLeave": true,
37 | "onBeforeRouteUpdate": true,
38 | "onBeforeUnmount": true,
39 | "onBeforeUpdate": true,
40 | "onDeactivated": true,
41 | "onErrorCaptured": true,
42 | "onMounted": true,
43 | "onRenderTracked": true,
44 | "onRenderTriggered": true,
45 | "onScopeDispose": true,
46 | "onServerPrefetch": true,
47 | "onUnmounted": true,
48 | "onUpdated": true,
49 | "onWatcherCleanup": true,
50 | "provide": true,
51 | "reactive": true,
52 | "readonly": true,
53 | "ref": true,
54 | "resolveComponent": true,
55 | "shallowReactive": true,
56 | "shallowReadonly": true,
57 | "shallowRef": true,
58 | "toRaw": true,
59 | "toRef": true,
60 | "toRefs": true,
61 | "toValue": true,
62 | "triggerRef": true,
63 | "unref": true,
64 | "useAttrs": true,
65 | "useCssModule": true,
66 | "useCssVars": true,
67 | "useId": true,
68 | "useLink": true,
69 | "useModel": true,
70 | "useRoute": true,
71 | "useRouter": true,
72 | "useSlots": true,
73 | "useTemplateRef": true,
74 | "watch": true,
75 | "watchEffect": true,
76 | "watchPostEffect": true,
77 | "watchSyncEffect": true
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/visualizer/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
--------------------------------------------------------------------------------
/visualizer/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pnpm-debug.log*
8 | lerna-debug.log*
9 |
10 | node_modules
11 | .DS_Store
12 | dist
13 | dist-ssr
14 | coverage
15 | *.local
16 |
17 | /cypress/videos/
18 | /cypress/screenshots/
19 |
20 | # Editor directories and files
21 | .vscode/*
22 | !.vscode/extensions.json
23 | .idea
24 | *.suo
25 | *.ntvs*
26 | *.njsproj
27 | *.sln
28 | *.sw?
29 |
30 | *.tsbuildinfo
31 |
--------------------------------------------------------------------------------
/visualizer/.prettierrc.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "$schema": "https://json.schemastore.org/prettierrc",
4 | "semi": false,
5 | "singleQuote": true,
6 | "printWidth": 100
7 | }
8 |
--------------------------------------------------------------------------------
/visualizer/auto-imports.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // noinspection JSUnusedGlobalSymbols
5 | // Generated by unplugin-auto-import
6 | export {}
7 | declare global {
8 | const EffectScope: typeof import('vue')['EffectScope']
9 | const computed: typeof import('vue')['computed']
10 | const createApp: typeof import('vue')['createApp']
11 | const customRef: typeof import('vue')['customRef']
12 | const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
13 | const defineComponent: typeof import('vue')['defineComponent']
14 | const effectScope: typeof import('vue')['effectScope']
15 | const getCurrentInstance: typeof import('vue')['getCurrentInstance']
16 | const getCurrentScope: typeof import('vue')['getCurrentScope']
17 | const h: typeof import('vue')['h']
18 | const inject: typeof import('vue')['inject']
19 | const isProxy: typeof import('vue')['isProxy']
20 | const isReactive: typeof import('vue')['isReactive']
21 | const isReadonly: typeof import('vue')['isReadonly']
22 | const isRef: typeof import('vue')['isRef']
23 | const markRaw: typeof import('vue')['markRaw']
24 | const nextTick: typeof import('vue')['nextTick']
25 | const onActivated: typeof import('vue')['onActivated']
26 | const onBeforeMount: typeof import('vue')['onBeforeMount']
27 | const onBeforeRouteLeave: typeof import('vue-router')['onBeforeRouteLeave']
28 | const onBeforeRouteUpdate: typeof import('vue-router')['onBeforeRouteUpdate']
29 | const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
30 | const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
31 | const onDeactivated: typeof import('vue')['onDeactivated']
32 | const onErrorCaptured: typeof import('vue')['onErrorCaptured']
33 | const onMounted: typeof import('vue')['onMounted']
34 | const onRenderTracked: typeof import('vue')['onRenderTracked']
35 | const onRenderTriggered: typeof import('vue')['onRenderTriggered']
36 | const onScopeDispose: typeof import('vue')['onScopeDispose']
37 | const onServerPrefetch: typeof import('vue')['onServerPrefetch']
38 | const onUnmounted: typeof import('vue')['onUnmounted']
39 | const onUpdated: typeof import('vue')['onUpdated']
40 | const onWatcherCleanup: typeof import('vue')['onWatcherCleanup']
41 | const provide: typeof import('vue')['provide']
42 | const reactive: typeof import('vue')['reactive']
43 | const readonly: typeof import('vue')['readonly']
44 | const ref: typeof import('vue')['ref']
45 | const resolveComponent: typeof import('vue')['resolveComponent']
46 | const shallowReactive: typeof import('vue')['shallowReactive']
47 | const shallowReadonly: typeof import('vue')['shallowReadonly']
48 | const shallowRef: typeof import('vue')['shallowRef']
49 | const toRaw: typeof import('vue')['toRaw']
50 | const toRef: typeof import('vue')['toRef']
51 | const toRefs: typeof import('vue')['toRefs']
52 | const toValue: typeof import('vue')['toValue']
53 | const triggerRef: typeof import('vue')['triggerRef']
54 | const unref: typeof import('vue')['unref']
55 | const useAttrs: typeof import('vue')['useAttrs']
56 | const useCssModule: typeof import('vue')['useCssModule']
57 | const useCssVars: typeof import('vue')['useCssVars']
58 | const useId: typeof import('vue')['useId']
59 | const useLink: typeof import('vue-router')['useLink']
60 | const useModel: typeof import('vue')['useModel']
61 | const useRoute: typeof import('vue-router')['useRoute']
62 | const useRouter: typeof import('vue-router')['useRouter']
63 | const useSlots: typeof import('vue')['useSlots']
64 | const useTemplateRef: typeof import('vue')['useTemplateRef']
65 | const watch: typeof import('vue')['watch']
66 | const watchEffect: typeof import('vue')['watchEffect']
67 | const watchPostEffect: typeof import('vue')['watchPostEffect']
68 | const watchSyncEffect: typeof import('vue')['watchSyncEffect']
69 | }
70 | // for type re-export
71 | declare global {
72 | // @ts-ignore
73 | export type { Component, ComponentPublicInstance, ComputedRef, DirectiveBinding, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, MaybeRef, MaybeRefOrGetter, VNode, WritableComputedRef } from 'vue'
74 | import('vue')
75 | }
76 |
--------------------------------------------------------------------------------
/visualizer/bun.lockb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cytix-software/AppSec-Detection-Framework/882e5a4cf4eb04cf563644bbf36c126cbeeb639c/visualizer/bun.lockb
--------------------------------------------------------------------------------
/visualizer/components.d.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 | /* prettier-ignore */
3 | // @ts-nocheck
4 | // Generated by unplugin-vue-components
5 | // Read more: https://github.com/vuejs/core/pull/3399
6 | export {}
7 |
8 | declare module 'vue' {
9 | export interface GlobalComponents {
10 | BarChart: typeof import('./src/components/BarChart.vue')['default']
11 | ChartControls: typeof import('./src/components/ChartControls.vue')['default']
12 | DashboardPage: typeof import('./src/components/DashboardPage.vue')['default']
13 | DataTable: typeof import('./src/components/DataTable.vue')['default']
14 | HeatmapChart: typeof import('./src/components/HeatmapChart.vue')['default']
15 | IconCommunity: typeof import('./src/components/icons/IconCommunity.vue')['default']
16 | IconDocumentation: typeof import('./src/components/icons/IconDocumentation.vue')['default']
17 | IconEcosystem: typeof import('./src/components/icons/IconEcosystem.vue')['default']
18 | IconSupport: typeof import('./src/components/icons/IconSupport.vue')['default']
19 | IconTooling: typeof import('./src/components/icons/IconTooling.vue')['default']
20 | RadarChart: typeof import('./src/components/RadarChart.vue')['default']
21 | RouterLink: typeof import('vue-router')['RouterLink']
22 | RouterView: typeof import('vue-router')['RouterView']
23 | ToolCoverageGap: typeof import('./src/components/ToolCoverageGap.vue')['default']
24 | TreemapChart: typeof import('./src/components/TreemapChart.vue')['default']
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/visualizer/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/visualizer/eslint.config.ts:
--------------------------------------------------------------------------------
1 | import pluginVue from 'eslint-plugin-vue'
2 | import { defineConfigWithVueTs, vueTsConfigs } from '@vue/eslint-config-typescript'
3 | import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
4 |
5 | // To allow more languages other than `ts` in `.vue` files, uncomment the following lines:
6 | // import { configureVueProject } from '@vue/eslint-config-typescript'
7 | // configureVueProject({ scriptLangs: ['ts', 'tsx'] })
8 | // More info at https://github.com/vuejs/eslint-config-typescript/#advanced-setup
9 |
10 | export default defineConfigWithVueTs(
11 | {
12 | name: 'app/files-to-lint',
13 | files: ['**/*.{ts,mts,tsx,vue}'],
14 | },
15 |
16 | {
17 | name: 'app/files-to-ignore',
18 | ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
19 | },
20 |
21 | pluginVue.configs['flat/essential'],
22 | vueTsConfigs.recommended,
23 | skipFormatting,
24 | )
25 |
--------------------------------------------------------------------------------
/visualizer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | ASDFviz
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/visualizer/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "visualizer",
3 | "version": "0.0.0",
4 | "private": true,
5 | "type": "module",
6 | "scripts": {
7 | "dev": "vite",
8 | "build": "run-p type-check \"build-only {@}\" --",
9 | "preview": "vite preview",
10 | "build-only": "vite build",
11 | "type-check": "vue-tsc --build",
12 | "lint": "eslint . --fix",
13 | "format": "prettier --write src/"
14 | },
15 | "dependencies": {
16 | "@vicons/antd": "^0.13.0",
17 | "apexcharts": "^4.5.0",
18 | "autoprefixer": "^10.4.20",
19 | "chart.js": "^4.4.8",
20 | "lodash": "^4.17.21",
21 | "lodash-es": "^4.17.21",
22 | "pinia": "^3.0.1",
23 | "vue": "^3.5.13",
24 | "vue-chartjs": "^5.3.2",
25 | "vue-router": "^4.5.0",
26 | "vue3-apexcharts": "^1.8.0",
27 | "yaml": "^2.7.0"
28 | },
29 | "devDependencies": {
30 | "@modyfi/vite-plugin-yaml": "^1.1.0",
31 | "@types/chart.js": "^2.9.41",
32 | "@types/lodash": "^4.17.15",
33 | "@types/lodash-es": "^4.17.12",
34 | "@types/node": "^22.13.4",
35 | "@vitejs/plugin-legacy": "^5.3.2",
36 | "@vitejs/plugin-vue": "^5.2.1",
37 | "@vue/eslint-config-prettier": "^10.2.0",
38 | "@vue/eslint-config-typescript": "^14.4.0",
39 | "eslint": "^8.57.0",
40 | "eslint-plugin-vue": "^9.24.1",
41 | "jiti": "^2.4.2",
42 | "naive-ui": "^2.31.0",
43 | "prettier": "^3.5.1",
44 | "typescript": "~5.0.0",
45 | "unplugin-auto-import": "^0.17.3",
46 | "unplugin-vue-components": "^0.26.0",
47 | "vite": "^5.2.8",
48 | "vue-tsc": "^2.2.2"
49 | },
50 | "module": "index.ts"
51 | }
52 |
--------------------------------------------------------------------------------
/visualizer/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cytix-software/AppSec-Detection-Framework/882e5a4cf4eb04cf563644bbf36c126cbeeb639c/visualizer/public/favicon.ico
--------------------------------------------------------------------------------
/visualizer/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Loading...
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
84 |
--------------------------------------------------------------------------------
/visualizer/src/assets/base.css:
--------------------------------------------------------------------------------
1 | /* color palette from */
2 | :root {
3 | --vt-c-white: #ffffff;
4 | --vt-c-white-soft: #f8f8f8;
5 | --vt-c-white-mute: #f2f2f2;
6 |
7 | --vt-c-black: #181818;
8 | --vt-c-black-soft: #222222;
9 | --vt-c-black-mute: #282828;
10 |
11 | --vt-c-indigo: #2c3e50;
12 |
13 | --vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
14 | --vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
15 | --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
16 | --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
17 |
18 | --vt-c-text-light-1: var(--vt-c-indigo);
19 | --vt-c-text-light-2: rgba(60, 60, 60, 0.66);
20 | --vt-c-text-dark-1: var(--vt-c-white);
21 | --vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
22 | }
23 |
24 | /* semantic color variables for this project */
25 | :root {
26 | --color-background: var(--vt-c-white);
27 | --color-background-soft: var(--vt-c-white-soft);
28 | --color-background-mute: var(--vt-c-white-mute);
29 |
30 | --color-border: var(--vt-c-divider-light-2);
31 | --color-border-hover: var(--vt-c-divider-light-1);
32 |
33 | --color-heading: var(--vt-c-text-light-1);
34 | --color-text: var(--vt-c-text-light-1);
35 |
36 | --section-gap: 160px;
37 | }
38 |
39 | @media (prefers-color-scheme: dark) {
40 | :root {
41 | --color-background: var(--vt-c-black);
42 | --color-background-soft: var(--vt-c-black-soft);
43 | --color-background-mute: var(--vt-c-black-mute);
44 |
45 | --color-border: var(--vt-c-divider-dark-2);
46 | --color-border-hover: var(--vt-c-divider-dark-1);
47 |
48 | --color-heading: var(--vt-c-text-dark-1);
49 | --color-text: var(--vt-c-text-dark-2);
50 | }
51 | }
52 |
53 | *,
54 | *::before,
55 | *::after {
56 | box-sizing: border-box;
57 | margin: 0;
58 | font-weight: normal;
59 | }
60 |
61 | body {
62 | min-height: 100vh;
63 | color: var(--color-text);
64 | background: var(--color-background);
65 | transition:
66 | color 0.5s,
67 | background-color 0.5s;
68 | line-height: 1.6;
69 | font-family:
70 | Inter,
71 | -apple-system,
72 | BlinkMacSystemFont,
73 | 'Segoe UI',
74 | Roboto,
75 | Oxygen,
76 | Ubuntu,
77 | Cantarell,
78 | 'Fira Sans',
79 | 'Droid Sans',
80 | 'Helvetica Neue',
81 | sans-serif;
82 | font-size: 15px;
83 | text-rendering: optimizeLegibility;
84 | -webkit-font-smoothing: antialiased;
85 | -moz-osx-font-smoothing: grayscale;
86 | }
87 |
--------------------------------------------------------------------------------
/visualizer/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/visualizer/src/assets/main.css:
--------------------------------------------------------------------------------
1 | @import './base.css';
2 |
--------------------------------------------------------------------------------
/visualizer/src/components/BarChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 | This chart shows a detection score percentage that indicates how effective a scanner is at identifying vulnerabilities overall. This score is adjusted to account for tests done for the same vulnerability across multiple tech stacks.
12 |
13 |
14 |
15 |
16 |
31 |
32 |
39 |
--------------------------------------------------------------------------------
/visualizer/src/components/ChartControls.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
12 |
21 |
22 |
23 |
24 |
39 |
40 |
54 |
--------------------------------------------------------------------------------
/visualizer/src/components/DashboardPage.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
AppSec Detection Framework Visualizer
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
398 |
399 |
465 |
--------------------------------------------------------------------------------
/visualizer/src/components/DataTable.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
36 |
37 |
38 |
39 |
45 |
46 |
47 |
48 |
204 |
205 |
257 |
--------------------------------------------------------------------------------
/visualizer/src/components/HeatmapChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 | This chart shows what percentage of vulnerabilities in each of the OWASP top 10 categories have been identified by the scanner.
12 |
13 |
14 |
15 |
16 |
31 |
32 |
39 |
--------------------------------------------------------------------------------
/visualizer/src/components/RadarChart.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/visualizer/src/components/data.ts:
--------------------------------------------------------------------------------
1 | import type { DockerCompose, VulnerabilitiesData, HydratedTest, HydratedHeatmapTest, CWEDetail } from './types'
2 |
3 | const dockerCompose: DockerCompose = (await import('../../../docker-compose.yml')).default
4 | const dataJson: VulnerabilitiesData = (await import('../../../data.json')).default
5 |
6 | export const loadData = () => {
7 | // Flatten the recordedTests object into an array with scanner information
8 | const flattenedTests = Object.entries(dataJson.recordedTests).flatMap(([scanner, scannerData]) =>
9 | scannerData.tests.map(test => ({ ...test, scanner }))
10 | )
11 |
12 | const hydratedHeatmapTests: HydratedHeatmapTest[] = flattenedTests.map((test) => ({
13 | ...test,
14 | profiles: dockerCompose.services[test.test]?.profiles || [],
15 | }))
16 |
17 | const testMap = new Map()
18 |
19 | dataJson.vulnerabilities.forEach((vul) => {
20 | vul.CWEDetails.forEach((cweDetail) => {
21 | const cwe = cweDetail.id
22 | flattenedTests.forEach((rt) => {
23 | if (rt.detectedCWEs.includes(cwe) || rt.undetectedCWEs?.includes(cwe)) {
24 | // Build "A01:2021 Broken Access Control" using the group from the vulnerability level
25 | const owaspWithGroup = `${vul.OWASP} ${vul.group}`
26 |
27 | const key = `${owaspWithGroup}|${cwe}|${rt.test}`
28 |
29 | if (!testMap.has(key)) {
30 | testMap.set(key, {
31 | owasp: owaspWithGroup,
32 | cwe,
33 | test: rt.test,
34 | detections: [],
35 | })
36 | }
37 |
38 | testMap.get(key).detections.push({
39 | scanner: rt.scanner,
40 | detected: rt.detectedCWEs.includes(cwe),
41 | profiles: dockerCompose.services[rt.test]?.profiles || [],
42 | })
43 | }
44 | })
45 | })
46 | })
47 |
48 | const hydratedTests = Array.from(testMap.values())
49 |
50 | return { hydratedHeatmapTests, hydratedTests, vulnerabilities: dataJson.vulnerabilities }
51 | }
52 |
53 | // Return all vulnerabilities matching a given OWASP code
54 | export function getDetailsByOwasp(owaspCode: string) {
55 | return dataJson.vulnerabilities
56 | .filter(vuln => vuln.OWASP === owaspCode)
57 | .flatMap(vuln => vuln.CWEDetails)
58 | }
59 |
60 | // Return the single vulnerability object matching a given CWE (assuming unique)
61 | export function getDetailsByCwe(cweId: number): CWEDetail | undefined {
62 | for (const vuln of dataJson.vulnerabilities) {
63 | const cweDetail = vuln.CWEDetails.find(detail => detail.id === cweId)
64 | if (cweDetail) {
65 | return cweDetail
66 | }
67 | }
68 | return undefined
69 | }
70 |
--------------------------------------------------------------------------------
/visualizer/src/components/icons/IconCommunity.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/visualizer/src/components/icons/IconDocumentation.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/visualizer/src/components/icons/IconEcosystem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/visualizer/src/components/icons/IconSupport.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/visualizer/src/components/icons/IconTooling.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
14 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/visualizer/src/components/types.ts:
--------------------------------------------------------------------------------
1 | export interface DockerService {
2 | image: string
3 | build: {
4 | context: string
5 | dockerfile: string
6 | }
7 | ports: string[]
8 | profiles: string[]
9 | }
10 |
11 | export interface CWEDetail {
12 | id: number
13 | title: string
14 | }
15 |
16 | export interface Vulnerability {
17 | OWASP: string
18 | CWEDetails: CWEDetail[]
19 | group: string
20 | }
21 |
22 | export interface RecordedTest {
23 | test: string
24 | detectedCWEs: number[]
25 | undetectedCWEs: number[]
26 | updatedAt: number
27 | }
28 |
29 | export interface HydratedHeatmapTest extends RecordedTest {
30 | scanner: string
31 | profiles: string[]
32 | }
33 |
34 | export interface HydratedTest {
35 | owasp: string
36 | cwe: number
37 | test: string
38 | detections: {
39 | scanner: string
40 | detected: boolean
41 | profiles: string[]
42 | }[]
43 | }
44 |
45 | export interface DockerCompose {
46 | services: {
47 | [key: string]: DockerService
48 | }
49 | }
50 |
51 | export interface VulnerabilitiesData {
52 | vulnerabilities: Vulnerability[]
53 | recordedTests: {
54 | [scanner: string]: {
55 | scanProfile: string
56 | tests: RecordedTest[]
57 | }
58 | }
59 | }
60 |
61 | export interface WeightedScore {
62 | scanner: string
63 | score: number
64 | }
65 |
--------------------------------------------------------------------------------
/visualizer/src/main.ts:
--------------------------------------------------------------------------------
1 | import './assets/main.css'
2 | import { createApp } from 'vue'
3 | import App from './App.vue'
4 | import router from './router'
5 | import VueApexCharts from 'vue3-apexcharts'
6 |
7 | const app = createApp(App)
8 | app.use(router)
9 | app.use(VueApexCharts)
10 | app.mount('#app')
11 |
--------------------------------------------------------------------------------
/visualizer/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import { createRouter, createWebHistory } from 'vue-router'
2 | import HomeView from '../views/HomeView.vue'
3 |
4 | const router = createRouter({
5 | history: createWebHistory(import.meta.env.BASE_URL),
6 | routes: [
7 | {
8 | path: '/',
9 | name: 'home',
10 | component: HomeView,
11 | }
12 | ],
13 | })
14 |
15 | export default router
16 |
--------------------------------------------------------------------------------
/visualizer/src/stores/counter.ts:
--------------------------------------------------------------------------------
1 | import { ref, computed } from 'vue'
2 | import { defineStore } from 'pinia'
3 |
4 | export const useCounterStore = defineStore('counter', () => {
5 | const count = ref(0)
6 | const doubleCount = computed(() => count.value * 2)
7 | function increment() {
8 | count.value++
9 | }
10 |
11 | return { count, doubleCount, increment }
12 | })
13 |
--------------------------------------------------------------------------------
/visualizer/src/views/HomeView.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/visualizer/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
3 | declare module '*.yml' {
4 | const content: any;
5 | export default content;
6 | }
7 |
8 | declare module '*.json' {
9 | const content: any;
10 | export default content;
11 | }
12 |
--------------------------------------------------------------------------------
/visualizer/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ESNext",
4 | "module": "ESNext",
5 | "allowJs": true,
6 | "strict": true,
7 | "jsx": "preserve",
8 | "jsxImportSource": "vue",
9 | "moduleResolution": "Node",
10 | "skipLibCheck": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "forceConsistentCasingInFileNames": true,
14 | "useDefineForClassFields": true,
15 | "resolveJsonModule": true,
16 | "experimentalDecorators": true,
17 | "sourceMap": true,
18 | "baseUrl": ".",
19 | "noImplicitAny": false,
20 | "strictNullChecks": false,
21 | "noEmit": true,
22 | "paths": {
23 | "@/*": ["src/*"]
24 | },
25 | "lib": ["ESNext", "DOM", "DOM.Iterable"],
26 | "outDir": "dist"
27 | },
28 | "include": [
29 | "src/**/*.ts",
30 | "src/**/*.d.ts",
31 | "src/**/*.tsx",
32 | "src/**/*.vue",
33 | "interfaces/src/*.ts",
34 | "components.d.ts",
35 | "auto-imports.d.ts",
36 | "vite.config.ts"
37 | ],
38 | "exclude": ["node_modules"]
39 | }
40 |
--------------------------------------------------------------------------------
/visualizer/vite.config.ts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite'
2 | import vue from '@vitejs/plugin-vue'
3 | import legacy from '@vitejs/plugin-legacy'
4 | import yaml from '@modyfi/vite-plugin-yaml'
5 | import path from 'path'
6 | import AutoImport from 'unplugin-auto-import/vite'
7 | import AutoComponent from 'unplugin-vue-components/vite'
8 |
9 | export default defineConfig({
10 | plugins: [
11 | vue(),
12 | legacy(),
13 | AutoImport({
14 | imports: ['vue', 'vue-router'],
15 | dts: true,
16 | eslintrc: { enabled: true },
17 | }),
18 | AutoComponent({ dts: true }),
19 | yaml(),
20 | ],
21 | server: {
22 | fs: {
23 | allow: [path.resolve('..')],
24 | },
25 | },
26 | resolve: {
27 | alias: {
28 | '@data': path.resolve(__dirname, '../'),
29 | },
30 | },
31 | })
32 |
--------------------------------------------------------------------------------