# Security Audit

Audit date: 2026-07-21

## Fixed

- Public pages no longer start sessions automatically from `config.php`.
- Session startup is explicit through `start_app_session()`.
- Admin/referral authenticated areas preserve idle timeout, regeneration, HttpOnly, Secure-on-HTTPS, and SameSite Strict.
- Pretty blog URL routing no longer falls through to the homepage.
- Unknown routes now return a friendly 404 with HTTP 404.
- `404.php` and `500.php` no longer hard-code `/strong-tower/` links.
- Public forms include CSRF, honeypot, rate limiting, duplicate locking, and server-side validation.
- Support ticket IDs no longer use `COUNT(*)`; random unique ticket codes prevent concurrency collisions.
- Referral codes no longer rely on a short random number; random hex suffixes are retried on collision.
- Resume validation checks extension, MIME, file magic, and DOCX structure.
- `cache/` and `logs/` are protected with `.htaccess`.
- `admin/setup-admin.php` remains local-only and is excluded from the production ZIP.
- Footer does not expose an admin console link.
- No demo admin password is inserted in `database.sql`.
- Homepage headers no longer expose `X-Powered-By`.
- Homepage no longer emits a public `PHPSESSID`; form pages still start sessions for CSRF.

## Route And Access Evidence

- `/strong-tower/`: 200, no `Set-Cookie`, no `X-Powered-By`.
- `/strong-tower/contact.php`: 200, CSRF session cookie present.
- `/strong-tower/config.php`: 403.
- `/strong-tower/database.sql`: 403.
- `/strong-tower/uploads/resumes/.htaccess`: 403.
- `/strong-tower/not-real-page`: 404.

## Form Concurrency Evidence

Concurrent local test marker: `STHHS_CONC_1784602819`.

- Care request: 5 concurrent POSTs, 5 HTTP 200 responses, 5 rows saved.
- General contact: 5 concurrent POSTs, 5 HTTP 200 responses, 5 rows saved.
- Customer support: 5 concurrent POSTs, 5 HTTP 200 responses, 5 rows saved.
- Support ticket uniqueness: 5 distinct ticket codes for 5 saved support rows.
- Cleanup: marked test rows removed; remaining counts were 0/0/0.

Duplicate-submission test:

- 2 identical concurrent general-contact POSTs returned HTTP 200.
- Saved rows: 1.
- Duplicate test row and recent lock/rate-limit records were removed afterward.

## Upload Test Evidence

PHP CLI validation tests:

```json
{
  "valid_pdf": true,
  "valid_docx": true,
  "disallowed_php": false,
  "renamed_executable": false,
  "incorrect_mime": false
}
```

Oversized uploads are rejected by the `jobs.php` server-side `> 5242880` byte check.

## Production-Safe Error Handling

- `display_errors`: Off
- `log_errors`: On
- Log target: `logs/php-errors.log`
- Public DB connection failures include `500.php` instead of raw exception output.
- Public SQL messages and stack traces are not shown.

## Remaining Verification Needed

- SMTP delivery must be verified with the production cPanel mailbox/routing configuration.
- Production cPanel should set `expose_php=Off`; the app also strips `X-Powered-By` at runtime.
- Authenticated admin click-through testing requires valid admin credentials. The local database has one admin account, but no password was available; an attempted temporary-admin test was rejected as too risky by the command reviewer.
