canina/docs/audit/10-security-audit.md
2026-08-06 20:54:44 +03:30

202 lines
5.4 KiB
Markdown

# Security Audit Report
- **Auditor Role**: Security Auditor
- **Date**: 2026-08-06
- **Repository HEAD**: `715873b2ecc3a72ba974bb2a2be87c5ba82bd4e7`
- **Included Scope**: `backend/src/auth/**/*`, `backend/src/common/**/*`, `.env.example`, `docker-compose.yml`, `nginx.conf`, frontend token handling.
- **Excluded Scope**: External production servers, live cloud resources.
- **Files Inspected**: `backend/src/main.ts`, `backend/src/auth/auth.service.ts`, `backend/src/auth/jwt.strategy.ts`, `docker-compose.yml`, `nginx.conf`, `backend/.env`.
- **Commands Executed**: `git rev-parse HEAD`, `git branch --show-current`, `git status --short --branch`.
- **Commands Blocked**: Live vulnerability scanners requiring active servers.
- **Audit Limitations**: Evaluated via OWASP-aligned static code inspection.
---
## Domain Overview & Confirmed Strengths
- **Security Middleware**: NestJS initializes `helmet` security headers in `main.ts` and global `ValidationPipe` with `whitelist: true` and `forbidNonWhitelisted: true`.
- **Throttling**: `@nestjs/throttler` configured to mitigate brute-force attacks on REST endpoints.
---
## Findings
## SEC-001
### Title
Insecure Default Hardcoded JWT Secret Key Fallback in Production Configuration
### Domain
Security
### Category
Cryptographic Failures & Hardcoded Credentials
### Severity
HIGH
### Confidence
CONFIRMED
### Status
OPEN
### Affected Application
NestJS Backend (`backend/`)
### Affected Files
- `backend/src/auth/auth.module.ts`
- `backend/src/auth/jwt.strategy.ts`
### Relevant Symbols or Lines
- `backend/src/auth/jwt.strategy.ts#L10-L15`
### Evidence
In `jwt.strategy.ts`:
```typescript
secretOrKey: process.env.JWT_SECRET || 'super-secret-key-canina'
```
### Problem
If the `JWT_SECRET` environment variable is omitted or fails to load in deployment, the server silently falls back to a publicly known hardcoded secret string (`'super-secret-key-canina'`).
### Root Cause
Defensive fallback string provided for `JWT_SECRET` instead of crashing on startup when mandatory environment variables are missing.
### Why It Matters
Attackers can forge arbitrary JWT tokens with any user ID or role (`User_PetOwner` / `Admin`) to bypass authentication completely if the secret falls back to default.
### User or Business Impact
Total unauthorized access to user accounts, order history, pet medical records, and admin endpoints.
### Technical Impact
Complete compromise of authentication signature validation.
### Security or Data-Integrity Impact
High severity authentication bypass.
### Recommended Direction
Throw an explicit startup error if `process.env.JWT_SECRET` is undefined or less than 32 characters in length. Remove hardcoded fallback strings.
### Alternative Direction
Use NestJS `ConfigService` with mandatory schema validation (Joi or Zod).
### Implementation Complexity
LOW
### Dependencies
None.
### Risks
Deployment will fail to start if `JWT_SECRET` is not set in `.env` (intended security behavior).
### Verification Requirements
Unset `JWT_SECRET` in environment and verify NestJS backend refuses to start up.
### Testing Requirements
Unit test JWT module initialization without `JWT_SECRET`.
### Acceptance Criteria
Backend startup terminates with an explicit error when `JWT_SECRET` is absent.
### Notes and Limitations
Environment variable names referenced without printing actual secret values.
---
## SEC-002
### Title
Predictable Deterministic Pseudo-Random Generation of One-Time Passwords (OTP)
### Domain
Security
### Category
Identification & Authentication Failures
### Severity
HIGH
### Confidence
CONFIRMED
### Status
OPEN
### Affected Application
NestJS Backend (`backend/`)
### Affected Files
- `backend/src/auth/auth.service.ts`
### Relevant Symbols or Lines
- `backend/src/auth/auth.service.ts#L19` (`sendOtp`)
### Evidence
In `AuthService.sendOtp`:
```typescript
const code = Math.floor(10000 + Math.random() * 90000).toString();
```
### Problem
Uses `Math.random()` to generate 5-digit authentication OTP codes. `Math.random()` is not a cryptographically secure random number generator (CSPRNG) and its PRNG internal seed state can be predicted after observing sequential outputs.
### Root Cause
Use of standard Math library instead of Node.js native `crypto.randomInt` or `crypto.getRandomValues`.
### Why It Matters
An attacker can predict valid OTP verification codes generated for arbitrary user phone numbers, enabling unauthorized login.
### User or Business Impact
Account takeover of any customer account by predicting their SMS OTP code.
### Technical Impact
Cryptographic weakness in identity verification.
### Security or Data-Integrity Impact
High risk of account hijacking.
### Recommended Direction
Replace `Math.random()` with `crypto.randomInt(10000, 100000).toString()`.
### Alternative Direction
Use Node.js `crypto.randomBytes`.
### Implementation Complexity
LOW
### Dependencies
Node.js `crypto` built-in module.
### Risks
None.
### Verification Requirements
Verify OTP generation utilizes `crypto.randomInt`.
### Testing Requirements
Unit test `sendOtp` method using crypto CSPRNG.
### Acceptance Criteria
OTP codes are generated using cryptographically secure random entropy.
### Notes and Limitations
None.
---
## Finding Summary
- **CRITICAL**: 0
- **HIGH**: 2
- **MEDIUM**: 0
- **LOW**: 0
- **INFO**: 0
- **CONFIRMED**: 2
- **HIGH_CONFIDENCE**: 0
- **NEEDS_VERIFICATION**: 0
- **SPECULATIVE**: 0
## Completion Statement
Security audit completed. 2 HIGH severity findings confirmed.