Skip to content

Latest commit

 

History

History
220 lines (154 loc) · 5.86 KB

File metadata and controls

220 lines (154 loc) · 5.86 KB

Penetration Test Report - Security Analysis

Field Value
Target ./my-webapp
Framework flask
Language python
Scan Date 2026-03-21T10:30:00

Table of Contents

Executive Summary

  • Total Issues Found: 3
  • Confirmed: 3
  • Needs Review: 0

Severity Breakdown

Severity Count
Critical 1
High 1
Medium 1
Low 0

Most Critical Issues

  • [CRITICAL] LSA-001: SQL Injection via unsanitized user input (confidence: 92%) - app.py:27 in get_user()
  • [HIGH] LSA-002: Hardcoded database credentials (confidence: 88%) - config.py:5
  • [MEDIUM] LSA-003: Login endpoint lacks brute-force protection (confidence: 75%) - auth.py:15 in login()

OWASP Top 10 Coverage

Category Status
A01: Broken Access Control Checked
A02: Cryptographic Failures Checked
A03: Injection Issue found (1)
A04: Insecure Design Checked
A05: Security Misconfiguration Issue found (1)
A06: Vulnerable and Outdated Components Checked
A07: Identification and Authentication Failures Issue found (1)
A08: Software and Data Integrity Failures Checked
A09: Security Logging and Monitoring Failures Checked
A10: Server-Side Request Forgery (SSRF) Checked

Findings by File

File Critical High Medium Low Total
app.py 1 0 0 0 1
config.py 0 1 0 0 1
auth.py 0 0 1 0 1

Detailed Findings

Critical Severity

LSA-001: SQL Injection via unsanitized user input

Field Detail
Category A03: Injection - SQL Injection
Severity CRITICAL
Status CONFIRMED
Location app.py:27 in get_user()
Confidence 92%

Description:

The get_user() function constructs a SQL query by directly interpolating the user_id parameter from request.args into the query string without any sanitization or parameterization. This allows an attacker to inject arbitrary SQL code.

Root Cause:

Unsanitized user input concatenated into SQL query using an f-string.

Impact:

An attacker can read, modify, or delete any data in the database. With sufficient privileges, they may execute system commands or escalate to full server compromise.

Exploitation Scenario:

  1. Attacker visits /user?id=1' OR 1=1--
  2. The application constructs the query: SELECT * FROM users WHERE id = '1' OR 1=1--'
  3. All user records are returned, including admin accounts and password hashes.

Exploit Details (HTTP Request):

GET /user?id=1'%20UNION%20SELECT%20username,password%20FROM%20users-- HTTP/1.1
Host: target.com

Evidence (Code Snippet):

@app.route('/user')
def get_user():
    user_id = request.args.get('id')
    query = f"SELECT * FROM users WHERE id = '{user_id}'"
    cursor.execute(query)

Remediation:

Use parameterized queries:

cursor.execute("SELECT * FROM users WHERE id = ?", (user_id,))

References:

  • OWASP Cheat Sheet - SQL Injection Prevention

Validation Reasoning:

Gate 1 (Evidence): The f-string query construction at line 27 clearly shows unsanitized input. Gate 2 (Exploitability): No parameterized queries, no input validation, no WAF indicated. Standard UNION-based attack path is viable. Gate 3 (Impact): Full database access including credential theft. Gate 4 (False Positive Check): This is a textbook SQL injection, not a best-practice note.


High Severity

LSA-002: Hardcoded database credentials

Field Detail
Category A05: Security Misconfiguration
Severity HIGH
Status CONFIRMED
Location config.py:5
Confidence 88%

Description:

Database connection string with plaintext username and password is hardcoded in the source code.

Root Cause:

Credentials stored directly in source code instead of environment variables or a secrets manager.

Impact:

Anyone with access to the repository (including public GitHub) can obtain database credentials and connect directly to the database.

Evidence (Code Snippet):

DB_URL = "postgresql://admin:s3cret_passw0rd@db.example.com:5432/production"

Remediation:

Use environment variables:

DB_URL = os.getenv("DATABASE_URL")

Medium Severity

LSA-003: Login endpoint lacks brute-force protection

Field Detail
Category A07: Identification and Authentication Failures
Severity MEDIUM
Status CONFIRMED
Location auth.py:15 in login()
Confidence 75%

Description:

The login endpoint checks username and password against the database but has no rate limiting, account lockout, CAPTCHA, or delay between failed attempts. An attacker can brute-force credentials at maximum speed.

Root Cause:

No throttling or lockout mechanism implemented on the authentication endpoint.

Exploit Details (HTTP Request):

POST /login HTTP/1.1
Content-Type: application/x-www-form-urlencoded

username=admin&password=FUZZ

(Use hydra, ffuf, or Burp Intruder with a wordlist to brute-force the password field)

Remediation:

Implement rate limiting (e.g., Flask-Limiter) and account lockout after N failed attempts:

@limiter.limit("5/minute")
@app.route('/login', methods=['POST'])
def login():
    ...

Scan Metadata

Metric Value
Files Scanned 8
Functions Found 15
Entry Points 6
Taint Flows 3
Packages Analyzed 6
Scan Duration 23.4s
LLM Tokens Used 18500