A Security Audit Checklist for Modern Applications
Why Should Security Audits Happen Before Incidents, Not After?
Security posture is cheapest to improve before the first incident because post-incident costs compound across response, forensics, notification, and the engineering time to patch what should have been caught proactively.
Most teams only think about security after something goes wrong. A credential leaks into a public repository, a customer reports unauthorized access, or a dependency vulnerability makes the news. By that point, the cost has already compounded: incident response, forensic investigation, customer notification, regulatory scrutiny, and the engineering time to patch what should have been caught months earlier.
At American Express, I led the development of CertaaS, an enterprise certificate automation platform that required 99.999% availability. When a service handles certificate lifecycles across an entire organization, security is not a feature you bolt on later. It is the foundation every other decision rests on. The architecture had to assume that any component could be compromised and still maintain integrity. That experience taught me something I carry into every engagement: security posture is cheapest to improve before the first incident, not after.
A security audit is not a penetration test. It is a structured review of your application, infrastructure, and operational practices against known vulnerability categories. The goal is to surface risks, prioritize them by likelihood and impact, and produce a remediation plan your team can actually execute. The checklist below reflects what I look at when reviewing a modern application stack, drawn from experience across enterprise financial services and startup environments.
How Do You Use the OWASP Top 10 as a Starting Framework?
The OWASP Top 10 provides a structured checklist of the most frequently appearing vulnerability categories in production systems, serving as a practical starting point rather than an exhaustive assessment.
The OWASP Top 10 remains the most practical starting point for application security review. It is not exhaustive, but it covers the vulnerability categories that appear most frequently in production systems. Rather than treating it as an academic exercise, I use it as a structured checklist for each engagement.
Here are the items I prioritize in every audit:
- Broken Access Control - Verify that authorization checks exist at every API endpoint, not just the frontend. Test for horizontal privilege escalation by attempting to access resources belonging to other users. Check that default deny is enforced rather than default allow.
- Injection - Review all database queries for parameterized input handling. Check ORM configurations for raw query escape paths. Examine any endpoint that accepts user input and passes it to a system command, template engine, or third-party API.
- Cryptographic Failures - Audit TLS configurations across all endpoints. Verify that sensitive data at rest uses strong encryption. Check for hardcoded encryption keys, weak hashing algorithms (MD5, SHA-1 for passwords), and expired certificates.
- Security Misconfiguration - Review default configurations on web servers, databases, and cloud services. Check for exposed admin panels, verbose error messages in production, and unnecessary open ports. Examine CORS policies for overly permissive origins.
- Vulnerable Dependencies - Run dependency scanning tools against the full dependency tree (not just direct dependencies). Flag any known CVEs and assess whether the vulnerable code paths are actually reachable in your application.
The OWASP list provides structure, but real audits go deeper. At JPMorgan, the Chase Offers platform processed millions of daily transactions across Visa, Amex, and Mastercard networks. Every API endpoint handling card-linked offer data needed authorization checks that went well beyond simple role-based access. We validated entitlements at the network level, the merchant level, and the individual offer level. The OWASP framework got us started, but the specific business logic required custom validation rules that no generic checklist would cover.
What Does Effective Secrets Management Look Like?
Effective secrets management stores every credential in a centralized secrets manager with automated rotation, scoped permissions, and regular audits of the full git history for any accidentally committed keys.
Secrets management is where I see the widest gap between what teams intend and what they actually practice. The intention is always good: “We use environment variables for secrets.” The reality is often less encouraging: API keys committed to version control six months ago, database credentials shared across environments, service accounts with full admin access because someone needed to debug a production issue and never revoked the permissions.
A thorough secrets audit covers several areas:
- Secret storage - Are credentials stored in a dedicated secrets manager (Hashicorp Vault, AWS Secrets Manager, or equivalent) or scattered across environment files, CI/CD variables, and application configs? Every secret should have exactly one canonical source.
- Rotation policy - How frequently are secrets rotated? Is rotation automated or manual? Manual rotation tends to mean rotation never happens. At Amex, CertaaS automated certificate renewal and improved processing efficiency by 600% precisely because manual renewal was unreliable at enterprise scale.
- Access scope - Does each service have credentials scoped to only the resources it needs? A microservice that reads from a single database table should not hold credentials with write access to every table in the schema. Apply least privilege aggressively.
- Git history - Scan the full git history for committed secrets, not just the current HEAD. Tools like
trufflehogandgitleaksautomate this process. If secrets are found in history, they must be rotated immediately since removing the commit is not sufficient because anyone who cloned the repository already has them. - Service account hygiene - Audit all service accounts and API keys. Remove any that are unused. Ensure each has an identifiable owner and a documented purpose. Orphaned service accounts are a common vector for unauthorized access.
I recommend Hashicorp Vault for teams that need centralized secrets management with dynamic credential generation. For AWS-native stacks, Secrets Manager with automatic rotation covers most use cases. The specific tool matters less than the discipline: every secret must be stored centrally, rotated automatically, and scoped to the minimum required access.
How Do Infrastructure and Application Security Layers Differ?
Infrastructure security focuses on the platform your application runs on, including network segmentation, IAM policies, and container images, while application security focuses on the code’s runtime behavior like input validation, authentication flows, and rate limiting.
A common mistake in security reviews is treating infrastructure and application security as a single concern. They overlap, but they require different expertise and different remediation strategies. Missing this distinction leads to audits that are thorough at one layer and blind at the other.
Infrastructure security focuses on the platform your application runs on:
- Network segmentation and firewall rules (are databases publicly accessible?)
- Container image scanning for OS-level vulnerabilities
- IAM policies and role boundaries in your cloud provider
- Logging and monitoring configuration (are security events being captured?)
- Backup encryption and disaster recovery procedures
- TLS termination points and certificate management
Application security focuses on the code and its runtime behavior:
- Input validation and output encoding across all user-facing endpoints
- Authentication flow security (token storage, session management, MFA)
- Authorization logic at the API layer, not just the UI layer
- Rate limiting and abuse prevention on public endpoints
- Error handling that avoids leaking internal state to callers
- Content Security Policy headers and other browser-level protections
At JPMorgan, when we modernized the Chase Offers platform from legacy Spring to Spring Boot and migrated from monolithic EC2 instances to containerized ECS architecture, the infrastructure security posture changed fundamentally. Container isolation provided stronger boundaries between services, but it also introduced new attack surfaces around container registries, image provenance, and orchestration APIs. The CI/CD pipeline we established included integrated security validation at both layers: static analysis on the application code and configuration scanning on the infrastructure definitions.
Your audit checklist should address both layers explicitly. For each finding, note whether it is an infrastructure concern, an application concern, or both. This distinction helps route remediation to the right team and prevents the common failure mode where developers assume infrastructure will handle something that infrastructure assumes the application handles.
How Do You Build a Remediation Roadmap That Teams Actually Follow?
A remediation roadmap that gets followed uses severity classification, honest effort estimates, phased delivery aligned to sprint cadence, clear validation criteria, and automated regression testing.
An audit that produces a 40-page PDF of findings and no actionable plan is an audit that changes nothing. The most valuable part of a security review is not the list of vulnerabilities. It is the remediation roadmap that translates findings into work your engineering team can execute within their existing sprint cadence.
Here is how I structure remediation roadmaps to maximize follow-through:
- Severity classification - Categorize each finding as Critical, High, Medium, or Low based on both exploitability and business impact. A SQL injection vulnerability on a public-facing endpoint is Critical. A missing security header on an internal admin page is Medium. This classification drives prioritization.
- Effort estimation - For each finding, estimate the engineering effort required to remediate. Be honest about complexity. A “just add parameterized queries” fix might touch 30 endpoints across 8 services. Teams need realistic time estimates to plan their work.
- Phased delivery - Group remediations into phases. Phase 1 covers Critical and High findings that can be resolved within two weeks. Phase 2 handles Medium findings over the next month. Phase 3 addresses Low findings and longer-term architectural improvements. This prevents the roadmap from feeling overwhelming.
- Validation criteria - Each remediation item needs a clear definition of done. “Fix the authentication issue” is not actionable. “Implement token refresh with a 15-minute expiry, add refresh token rotation, and verify with integration tests covering expired token, stolen refresh token, and concurrent session scenarios” is actionable.
- Automated regression - Where possible, encode security requirements as automated tests. Add SAST (static analysis) to the CI pipeline. Configure dependency scanning to block merges when critical CVEs are detected. Automate what you can so that remediated issues stay remediated.
The roadmap should integrate into your team’s existing workflow. If you use Jira, create tickets. If you use GitLab issues, create issues. If you run two-week sprints, scope the phases to align with sprint boundaries. A security roadmap that requires a separate project management process will be ignored.
From my experience at Amex and JPMorgan, the teams that successfully remediate security findings are the ones that treat them like any other engineering work: scoped tickets, assigned owners, sprint commitments, and definition of done. The teams that fail are the ones that put the audit report in a shared drive and plan to “get to it later.”
What Practical Checklist Can You Use Today?
The following consolidated checklist covers the essential security items across application, infrastructure, and operational layers that every modern application should verify.
- Authorization checks enforced at the API layer, not just the UI
- All database queries use parameterized inputs
- TLS enforced on every endpoint (no mixed content)
- Sensitive data encrypted at rest with strong algorithms (AES-256 or equivalent)
- No secrets committed to version control (scan full git history)
- All secrets stored in a centralized secrets manager with automated rotation
- Service accounts scoped to minimum required permissions
- Dependency scanning integrated into CI/CD with blocking on critical CVEs
- Container images scanned for OS-level vulnerabilities before deployment
- Network segmentation prevents direct public access to databases
- Rate limiting configured on all public-facing endpoints
- Error responses do not leak stack traces, internal paths, or system details
- Security headers configured: CSP, HSTS, X-Frame-Options, X-Content-Type-Options
- Authentication tokens use short expiry with secure refresh mechanisms
- Logging captures authentication failures, authorization denials, and input validation rejections
- IAM roles and policies reviewed quarterly for unused or overly broad permissions
- Backup and recovery procedures tested with documented restore times
- CORS policies restricted to specific allowed origins
- Static analysis (SAST) runs on every pull request
- Incident response plan documented and accessible to the on-call team
This list is a starting point, not an endpoint. Every application has domain-specific security considerations that a generic checklist cannot capture. Financial services applications need PCI-DSS compliance checks. Healthcare applications need HIPAA controls. The value of working with someone who has operated in these environments is the ability to identify what your specific application needs beyond the standard framework.
Related Posts
- Infrastructure Hardening: Lessons from Enterprise Scale
- Building CI/CD Pipelines from Zero to Production
Want a security audit before your next incident? Schedule a free compliance audit to get a practical security review for your application.