From 7474422cefb733ca834e038de3fcba2f2569e3c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Po=C3=A7as?= Date: Thu, 17 Sep 2026 15:24:06 -0400 Subject: [PATCH 1/5] Add SAST scanner ground-truth endpoint --- src/Scanner/SASTScanner.php | 81 +++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 src/Scanner/SASTScanner.php diff --git a/src/Scanner/SASTScanner.php b/src/Scanner/SASTScanner.php new file mode 100644 index 0000000..2c22207 --- /dev/null +++ b/src/Scanner/SASTScanner.php @@ -0,0 +1,81 @@ + FileUpload::class, + "filePath" => "src/FileUploadVulnerability/FileUpload.php", + "methods" => [ + "level1", + "level2", + "level3", + "level4", + "level5", + "level6", + "level7", + "level8", + "level9", + "level10", + "level11", + ], + "cwe" => "CWE-434", + "type" => "Unrestricted File Upload", + ], + [ + "class" => MagicHash::class, + "filePath" => "src/MagicHashVulnerability/MagicHash.php", + "methods" => ["level1", "level2"], + "cwe" => "CWE-704", + "type" => "Magic Hash Exploitation", + ], + [ + "class" => NoSQLInjection::class, + "filePath" => "src/NoSQLInjectionVulnerability/NoSQLInjection.php", + "methods" => ["level1", "level2", "level3"], + "cwe" => "CWE-943", + "type" => "MongoDB NoSQL Injection", + ], + [ + "class" => NoSQLInjection::class, + "filePath" => "src/NoSQLInjectionVulnerability/NoSQLInjection.php", + "methods" => ["level4"], + "cwe" => "CWE-256", + "type" => "Insecure Credential Storage", + ], + ]; + + private function buildScannerRows(): array + { + $rows = []; + + foreach (self::CATALOG as $entry) { + foreach ($entry["methods"] as $methodName) { + $method = new ReflectionMethod($entry["class"], $methodName); + $rows[] = [ + "cwe" => $entry["cwe"], + "filePath" => $entry["filePath"], + "line" => (int) $method->getStartLine(), + "numberOfSources" => 1, + "type" => $entry["type"], + ]; + } + } + + return $rows; + } + + function sast(): void + { + header("Content-type: application/json"); + echo json_encode($this->buildScannerRows(), JSON_UNESCAPED_SLASHES); + } +} From 035334d8d82387744e7cd456c643b1d70f8af489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Po=C3=A7as?= Date: Thu, 17 Sep 2026 15:24:25 -0400 Subject: [PATCH 2/5] Register SAST scanner route --- src/framework/Bootstrap.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/framework/Bootstrap.php b/src/framework/Bootstrap.php index aa3d668..f0075cf 100644 --- a/src/framework/Bootstrap.php +++ b/src/framework/Bootstrap.php @@ -6,12 +6,14 @@ use nosqlinjection\NoSQLInjectionSeeder; use ReflectionClass; use scanner\DASTScanner; +use scanner\SASTScanner; use framework\Mapper; require __DIR__ . "/../FileUploadVulnerability/FileUpload.php"; require __DIR__ . "/../MagicHashVulnerability/MagicHash.php"; require __DIR__ . "/../NoSQLInjectionVulnerability/NoSQLInjection.php"; require __DIR__ . "/../NoSQLInjectionVulnerability/NoSQLInjectionSeeder.php"; require __DIR__ . "/../Scanner/DASTScanner.php"; +require __DIR__ . "/../Scanner/SASTScanner.php"; require __DIR__ . "/Mapper.php"; class Bootstrap { @@ -127,6 +129,9 @@ function __construct() $this->routing_url_to_mapper[ "/VulnerableApp-php/scanner/dast" ] = new Mapper(new ReflectionClass(DASTScanner::class), "dast"); + $this->routing_url_to_mapper[ + "/VulnerableApp-php/scanner/sast" + ] = new Mapper(new ReflectionClass(SASTScanner::class), "sast"); } } ?> From a2d794c90da71756738e57f5d20b3228b9029f7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Po=C3=A7as?= Date: Thu, 17 Sep 2026 15:24:36 -0400 Subject: [PATCH 3/5] Validate SAST scanner responses --- .github/workflows/php.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index 7bcfd21..2848fb1 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -31,6 +31,12 @@ jobs: --form 'file=@upload-test.png;type=image/png' | grep --quiet '"isValid":true' curl --fail --silent http://localhost:8080/VulnerableApp-php/images/upload-test.png \ | grep --quiet --fixed-strings --line-regexp 'test image' + - name: Run SAST scanner integration checks + run: | + curl --fail --silent http://localhost:8080/VulnerableApp-php/scanner/sast \ + | python3 -c 'import json, sys; data = json.load(sys.stdin); required = {"cwe", "filePath", "line", "numberOfSources", "type"}; assert data and all(required <= set(item) for item in data)' + curl --fail --silent http://localhost/scanner/sast \ + | python3 -c 'import json, sys; data = json.load(sys.stdin); assert data.get("VulnerableApp-php")' - name: Stop services if: always() run: docker compose down --volumes From 51a783ffc8de3689eec441533f91113738e0139d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Po=C3=A7as?= Date: Thu, 17 Sep 2026 15:48:38 -0400 Subject: [PATCH 4/5] docs: document SAST scanner methods --- src/Scanner/SASTScanner.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Scanner/SASTScanner.php b/src/Scanner/SASTScanner.php index 2c22207..2e4857d 100644 --- a/src/Scanner/SASTScanner.php +++ b/src/Scanner/SASTScanner.php @@ -53,6 +53,11 @@ class SASTScanner ], ]; + /** + * Builds the SAST ground-truth rows for all cataloged vulnerable methods. + * + * @return array + */ private function buildScannerRows(): array { $rows = []; @@ -73,6 +78,9 @@ private function buildScannerRows(): array return $rows; } + /** + * Emits the SAST ground-truth catalog as JSON for facade aggregation. + */ function sast(): void { header("Content-type: application/json"); From de6924015ddc874f142bc2fdfd84b004958a05e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20Po=C3=A7as?= Date: Thu, 17 Sep 2026 15:48:57 -0400 Subject: [PATCH 5/5] docs: document Bootstrap route registration --- src/framework/Bootstrap.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/framework/Bootstrap.php b/src/framework/Bootstrap.php index f0075cf..087379b 100644 --- a/src/framework/Bootstrap.php +++ b/src/framework/Bootstrap.php @@ -47,6 +47,9 @@ function get_vulnerability_definitions(): array return $vulnerability_definitions; } + /** + * Registers vulnerability providers and application routes, including scanner endpoints. + */ function __construct() { NoSQLInjectionSeeder::seedIfRequired();