Security Testing Policy
Security Testing Policy
Project / Organization: ALAI Holding AS — Drop Payment App Policy Number: POL-SEC-TEST-001 Version: 1.0 Date: 2026-02-23 Author: Security Architect Status: Draft Reviewers: CISO, Engineering Lead, CTO Next Review: 2027-02-23 Classification: Confidential
Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 0.1 | 2026-02-23 | Security Architect | Initial draft — Drop security testing methodology |
1. Purpose & Scope
Purpose: This policy defines the security testing methodology, tools, frequency, and remediation requirements for all systems operated by ALAI Holding AS for the Drop payment app. Security testing is mandatory — no system goes to production without completing applicable security tests.
Regulatory basis:
- IKT-forskriften (FOR-2003-05-21-630) §§ 5-6 — ICT security verification
- DORA (EU) 2022/2554 Art. 24-25 — Digital operational resilience testing
- Finanstilsynet licensing requirements — penetration test before production launch
- GDPR Art. 32(1)(d) — regular testing of technical measures
Scope:
- All production APIs and endpoints (
getdrop.no,api.getdrop.no) - All AWS infrastructure (App Runner, S3, KMS, Secrets Manager)
- All CI/CD pipelines and build systems
- All third-party integrations (BankID, Sumsub, Open Banking partners)
- Developer workstations handling Confidential or Restricted data
Policy Owner: CISO ([email protected]) Operational Owner: Security team + Engineering Lead
2. Security Testing Methodology
Approach: Shift-left security — testing integrated throughout development, not bolted on at the end.
Testing layers:
Development Phase
+-- Unit security tests — Vitest (current: 20+ security-specific tests)
+-- SCA — npm audit (every commit, automated)
+-- Secret scanning — detect leaked credentials (every commit)
Build / CI Phase
+-- SAST — static code analysis (every PR — planned Phase 2)
+-- SCA — dependency vulnerability check (every PR)
+-- Secret scanning — full scan (every PR)
Deployment Phase
+-- DAST — OWASP ZAP against staging (planned — Phase 3)
+-- API security scan — endpoint fuzzing (planned — Phase 3)
Operational Phase
+-- Vulnerability assessment — external attack surface (quarterly)
+-- Penetration test — manual expert testing (before Phase 3 launch)
+-- Post-incident review — regression tests after any security incident
3. Current Security Test Coverage
3.1 Vitest Unit Security Tests
Status: Implemented — 20+ security-specific tests
Source: src/drop-app/src/__tests__/
| Test Category | Test | Source |
|---|---|---|
| Authentication | JWT secret required in production | auth.test.ts |
| Authentication | Cookie: httpOnly=true, secure=true, sameSite=strict | auth.test.ts |
| Authentication | JWT contains setIssuedAt() | auth.test.ts |
| Authentication | Session revocation: revoked token rejected | auth.test.ts |
| Authentication | Logout revokes all user sessions | auth.test.ts |
| Password | bcrypt used — not SHA-256 | utils-server.test.ts |
| Password | bcrypt cost factor >= 12 | utils-server.test.ts |
| Password | SHA-256 hash rejected as invalid (fix C4) | utils-server.test.ts |
| Input Validation | IBAN checksum validation | validation.test.ts |
| Input Validation | Currency whitelist enforced | validation.test.ts |
| Input Validation | Language whitelist enforced | validation.test.ts |
| Input Validation | Amount: NaN/Infinity rejected | validation.test.ts |
| Input Validation | HTML tags stripped by sanitizeText() | validation.test.ts |
| SQL Injection | Parameterized queries for all user inputs | db.test.ts |
| Rate Limiting | Auth rate limit: 10/60s enforced | middleware.test.ts |
| Rate Limiting | Transaction rate limit: 10/60s enforced | middleware.test.ts |
| CSRF | Origin header validated | middleware.test.ts |
| CSRF | Invalid origin rejected | middleware.test.ts |
| IDOR | Transaction query scoped to user_id | transactions.test.ts |
| IDOR | Recipient query scoped to user_id | recipients.test.ts |
| Feature Flags | Cards endpoint returns 404 when flag disabled | feature-flags.test.ts |
3.2 Running the Security Test Suite
# Run all security tests
cd src/drop-app && npx vitest run --reporter verbose
# Run specific security test file
npx vitest run src/__tests__/auth.test.ts
# Run with coverage
npx vitest run --coverage
Blocking criteria: All security tests MUST pass before merge to main branch.
4. Testing Types, Tools & Schedule
4.1 SCA — Software Composition Analysis
Status: Implemented (npm audit)
| Property | Value |
|---|---|
| Tool | npm audit (built-in) + GitHub Dependabot (planned) |
| Frequency | Every commit (pre-commit hook) + every PR |
| Blocking | YES — Critical CVE blocks merge |
Current dependency security status (2026-02-13 audit):
| Package | Version | Risk | Status |
|---|---|---|---|
jose |
^6.1.3 | Low | No known CVEs |
bcryptjs |
^3.0.3 | Low | No known CVEs |
better-sqlite3 |
^12.6.2 | Low | No known CVEs |
next |
16.1.6 | Low | Recent version |
react |
19.2.3 | Low | Latest major |
radix-ui |
^1.4.3 | Low | UI only — no known CVEs |
Source: ~/ALAI/products/Drop/security/drop-security-rapport.md
Dependency update policy:
- Security patches (Critical/High): Merge within SLA (see §5)
- Minor security updates: Merge within 14 days
- Major updates: Planned migration within 90 days
Approved licenses: MIT, Apache 2.0, BSD (2-clause, 3-clause), ISC
4.2 SAST — Static Application Security Testing
Status: Planned (Phase 2)
| Property | Value |
|---|---|
| Tool | Semgrep or CodeQL (via GitHub Advanced Security) |
| Frequency | Every PR (full scan) |
| Languages | TypeScript, JavaScript |
| Blocking | YES — Critical or High findings block merge |
SAST rules in scope (when implemented):
- SQL injection detection (parameterized queries validation)
- JWT algorithm confusion (
alg: nonedetection) - Hardcoded secrets / credentials
- Insecure cryptography (MD5, SHA-1, DES, RC4)
- Path traversal / LFI
- IDOR patterns (database queries without user_id scoping)
- Missing authentication middleware
4.3 DAST — Dynamic Application Security Testing
Status: Planned (Phase 3 — before production launch)
| Property | Value |
|---|---|
| Tool | OWASP ZAP (planned) |
| Frequency | Every deployment to staging + weekly full scan |
| Target | https://staging.getdrop.no — NEVER production without CISO written approval |
| Blocking | YES — deployment halted if Critical finding discovered |
DAST scan scope:
- All 24 API endpoints (authenticated + unauthenticated)
- Authentication flows (login, registration, logout, session handling)
- Rate limiting (verify 10/60s limits enforced)
- CSRF protection (Origin header validation)
- Input validation (IBAN, currency, language, amount)
- Security headers presence (HSTS, CSP, X-Frame-Options, etc.)
- SSL/TLS configuration (TLS 1.3, no TLS 1.0/1.1)
- JWT handling (expiry, algorithm, revocation)
- Feature flag enforcement (cards endpoints return 404 when disabled)
4.4 Penetration Testing
Status: Required before Phase 3 production launch (Finanstilsynet licensing requirement)
| Property | Value |
|---|---|
| Frequency | Before production launch + annual thereafter |
| Scope | Full application + API + AWS infrastructure |
| Methodology | OWASP Testing Guide v4.2 + PTES |
| Provider | External security firm (not yet selected) |
| Blocking | Critical findings: system taken offline until remediated |
Penetration test scope:
In-scope:
- Staging pre-launch: https://staging.getdrop.no
- Production (after launch): https://getdrop.no, https://api.getdrop.no
- Authentication flows (login, registration, BankID OIDC callback — Phase 2)
- All 24 authenticated API endpoints
- Session management (JWT, cookie handling, revocation)
- Rate limiting and CSRF protection
- AWS App Runner configuration
- Cloudflare WAF configuration
Out-of-scope:
- Denial of service attacks
- Social engineering of staff without prior approval
- AWS infrastructure itself (AWS global responsibility)
- BankID Norge AS systems
- Sumsub systems
Rules of engagement:
- Testing window: To be agreed in writing with provider
- Notify before testing: [email protected]
- Halt on critical finding: Immediately notify [email protected] + CTO
Key test areas for Drop:
- JWT manipulation (algorithm confusion, expiry bypass, forged tokens)
- Session revocation bypass (sessions table manipulation)
- IDOR attacks (user_id scoping validation across all 24 endpoints)
- Rate limiting bypass (IP spoofing via X-Forwarded-For)
- CSRF (Origin header bypass)
- SQLi in all 24 endpoints (parameterized query verification)
- BankID OIDC callback manipulation (Phase 2)
- Feature flag bypass (cards endpoints when disabled)
- Foedselsnummer exposure (ensure never in plaintext logs or API responses)
5. Vulnerability Classification & Remediation SLAs
5.1 Severity Classification (CVSS v3.1)
| Severity | CVSS Score | Drop-Specific Definition |
|---|---|---|
| Critical | 9.0-10.0 | RCE, auth bypass without credentials, mass PII exfiltration, JWT forgery, foedselsnummer exposure |
| High | 7.0-8.9 | Privilege escalation, IDOR (cross-user data access), auth bypass (authenticated), SQL injection |
| Medium | 4.0-6.9 | CSRF, reflected XSS, rate limit bypass, information disclosure |
| Low | 0.1-3.9 | Version disclosure, weak error messages, minor misconfigurations |
| Informational | N/A | Best practice recommendations |
5.2 Remediation SLAs
| Severity | SLA | Action on Breach of SLA |
|---|---|---|
| Critical | Containment in 4h; full remediation in 24 hours | Emergency — CISO + CTO + CEO. System taken offline if risk cannot be mitigated. |
| High | 7 calendar days | Escalate to CISO. Engineering Lead must approve extension. |
| Medium | 30 calendar days | Engineering Lead tracks. Exception requires Security team sign-off. |
| Low | 90 calendar days | Tracked in backlog. Reviewed in quarterly security review. |
| Informational | Next sprint (best effort) | Not SLA-bound. |
SLA tracking: GitHub Issues with label security-finding + severity label.
6. Security Code Review Checklist
Required for every PR touching authentication, authorization, payment processing, PII, or cryptography:
Authentication & Authorization:
- No hardcoded credentials, JWT secrets, or API keys
- Password hashing uses bcrypt (cost >= 12) — SHA-256 explicitly rejected (fix C4)
- JWT validation: signature, expiry,
iatclaim verified viajose - Session revocation: all protected endpoints check sessions table for
revoked = 0 - No role flags from user-supplied input
- All protected endpoints have authentication middleware applied
- Logout revokes sessions server-side (not just clears cookie)
Input Validation:
- All user inputs validated using Drop validators (validateAmount, validateIBAN, validateCurrency, validateLanguage, sanitizeText)
- All database operations use parameterized
?queries — no string concatenation - User data queries include
AND user_id = ?scoping (IDOR prevention) - No eval(), exec(), or shell command interpolation with user input
Cryptography:
- No MD5, SHA-1, DES, RC4 (per data-encryption-policy.md §2.2)
- Random values use
crypto.randomBytes()— not Math.random() - IVs/nonces are random (96-bit minimum) and never reused
- No cryptographic keys in source code, logs, or error messages
Error Handling:
- No stack traces or internal paths in API error responses
- Generic messages for authentication failures (no user enumeration)
- Errors logged to Sentry internally but not exposed in API responses
Data Handling:
- Foedselsnummer not logged in plaintext (never in Sentry, BetterStack, console.log)
- Sensitive data not in query parameters (use POST body)
- Feature flags checked before any cards-related endpoint
- AML retention: user data deletion respects 5-year retention (Hvitvaskingsloven § 30)
Dependencies:
- New dependencies reviewed with
npm auditbefore adding - No end-of-life packages introduced
- License compatible (MIT, Apache 2.0, BSD, ISC)
7. Security Testing in CI/CD Pipeline
Current pipeline (MVP):
Developer Commit
+-- Pre-commit hook: npm audit (SCA)
|
v
Git Push -> PR
|
v
Vitest security tests (20+ tests)
|
v (all pass)
Merge to main
|
v
Deploy to AWS App Runner
Target pipeline (Phase 2+):
flowchart LR
COMMIT[Developer\nCommit] -->|Pre-commit| SCA_INC[npm audit\nSCA check]
SCA_INC -->|Pass| PUSH[Git Push]
PUSH --> PR[Pull Request]
PR --> VITEST[Vitest\nSecurity Tests]
PR --> SAST[SAST\nSemgrep/CodeQL]
PR --> SCA_FULL[npm audit\nFull scan]
PR --> SECRET[Secret\nScanning]
VITEST & SAST & SCA_FULL & SECRET -->|All pass| BUILD[Build\nDrop App]
BUILD --> STAGING[Deploy to\nStaging]
STAGING --> DAST[OWASP ZAP\nDAST Scan]
DAST -->|Pass| GATE{Security\nGate}
GATE -->|Pass| PROD[Deploy to\nProduction]
GATE -->|Fail| BLOCK[Block Deploy\nAlert [email protected]]
Pipeline security gate criteria:
| Gate | Tool | Blocking Criteria |
|---|---|---|
| Pre-commit | npm audit | Critical CVE |
| PR gate 1 | Vitest security tests | Any test failure |
| PR gate 2 | SAST (Phase 2) | Critical or High finding |
| PR gate 3 | npm audit full | Critical CVE |
| PR gate 4 | Secret scanning | Any detected secret |
| Post-staging | DAST (Phase 3) | Critical or High dynamic finding |
8. Security Audit History
| Date | Type | Provider | Findings | Status |
|---|---|---|---|---|
| 2026-02-12 | Full security audit | Internal (Security Architect) | 4C / 5H / 6M / 4L | Complete |
| 2026-02-13 | Hardening verification | Internal | 0C / 0H / 2M / 4L | Complete |
| TBD (Phase 3) | External penetration test | TBD | — | Planned — required before launch |
| TBD (Phase 3+) | Annual pentest | TBD | — | Annual thereafter |
Source: ~/ALAI/products/Drop/security/drop-security-rapport.md
Security Hardening Summary (2026-02-13)
| Finding | ID | Status |
|---|---|---|
Card data: only last_four + token_ref stored (no PAN/CVV) |
C1 | Resolved |
Demo credentials gated behind NODE_ENV !== 'production' |
C2 | Resolved |
| SHA-256 password support removed — bcrypt only | C4 | Resolved |
| Session revocation implemented and active | C6/H1 | Resolved |
| Input sanitization applied to all text fields | H4 | Resolved |
| Notification IDs validated (max 100, format check) | M5 | Resolved |
| Settings: currency/language validated against whitelists | M6 | Resolved |
Remaining items:
| Finding | ID | Type | Plan |
|---|---|---|---|
CSP: unsafe-inline/unsafe-eval required by Next.js |
M1 | Medium | Nonce-based CSP in Phase 3 |
Proxy HOSTNAME config |
M2 | Medium | Resolve in Phase 2 AWS config |
9. Reporting Format
9.1 Individual Finding
Finding ID: VULN-{YEAR}-{SEQUENCE}
Title: {SHORT_DESCRIPTION}
Severity: Critical / High / Medium / Low
CVSS Score: {SCORE} (v3.1)
Description:
{DETAILED_DESCRIPTION}
Affected Endpoint / File:
- {ENDPOINT_OR_FILE}: {URL_OR_LINE_NUMBER}
Proof of Concept:
{STEPS_TO_REPRODUCE}
Impact:
{WHAT_AN_ATTACKER_CAN_DO}
GDPR/AML Implications:
{IF_PERSONAL_DATA_OR_FINANCIAL_DATA_AFFECTED}
Remediation:
{SPECIFIC_FIX}
Owner: {ASSIGNED_ENGINEER}
SLA Due Date: {DATE}
Status: Open / In Progress / Resolved / Accepted Risk
10. Metrics & KPIs
| Metric | Target | Reporting Frequency |
|---|---|---|
| Critical findings resolved within SLA | 100% | Monthly |
| High findings resolved within SLA | 100% | Monthly |
| Vitest security test pass rate | 100% (blocking) | Every PR |
| MTTR — Critical | < 24 hours | Per incident |
| MTTR — High | < 7 days | Monthly |
| Open High+ findings | 0 at launch | Monthly |
| Annual penetration test completed | Yes (before Phase 3) | Annual |
| npm audit Critical CVEs | 0 in production | Continuous |
11. Bug Bounty Program
Status: Planned (Phase 3 — post-launch) Platform: Intigriti or HackerOne
Responsible disclosure (interim — before bug bounty): Report security vulnerabilities to [email protected].
- Acknowledgment: within 1 business day
- Triage: within 5 business days
- Safe harbor: researchers acting in good faith are protected from legal action
Approval
| Role | Name | Date | Signature |
|---|---|---|---|
| Author | Security Architect | 2026-02-23 | |
| CISO | |||
| Engineering Lead | |||
| CTO | |||
| Management |