Exercise: Compliance Readiness Audit
This exercise applies the security, IP, and compliance concepts from Module 7 to an existing codebase. You will audit a real project for AI tool readiness.
Overview
The BoxyHQ SaaS Starter Kit is a Next.js template for enterprise SaaS products. It has authentication, team management, payment processing, SAML SSO, and webhook integrations. This means it has the usual mess of sensitive data: API keys, OAuth credentials, database connection strings, encryption secrets.
The task: audit this repository as if your team is about to start using Claude Code and Codex on it. The goal is not to find every secret. It is to build an approach you can repeat on other projects, identifying the biggest risks and turning them into policies with teeth.
The scenario
Your organization wants to use Claude Code and Codex for development. Security wants an audit before anyone enables these tools. They want to know:
- What sensitive data is in this repository?
- How should it be classified?
- What tool settings will protect it?
- What policies should govern AI tool usage here?
You will produce three things: a sensitive data inventory, a classification mapping, and tool configuration files.
Setup
Clone the repository:
git clone https://github.com/boxyhq/saas-starter-kit.git
cd saas-starter-kitExplore the project structure:
ls -la
cat .env.example
ls -la prisma/Review the documentation:
cat README.md | head -100Do not run npm install yet.
You want to examine the repository at rest, before adding dependencies or running code.
Phase 1: Sensitive data inventory
Find files and patterns that contain sensitive data (or might). Work systematically rather than poking around randomly.
Manual reconnaissance
Start with common sensitive file patterns:
# Environment files
ls -la .env* 2>/dev/null
# Configuration files
find . -name "*.config.*" -o -name "config.*" | head -20
# Certificate and key files
find . -name "*.pem" -o -name "*.key" -o -name "*.crt" 2>/dev/null
# Docker configuration
ls docker* Dockerfile* 2>/dev/nullExamine the .env.example file carefully.
It documents every environment variable the application expects.
Even without real values, it shows you what secrets production will need:
cat .env.exampleThe .env.example file has no actual secrets, just placeholders.
But it maps out the secrets surface area.
That information is useful to someone planning an attack.
Automated scanning
Run a secret scanner to catch patterns you missed:
# Using Gitleaks (if installed)
gitleaks detect --source . --report-format json --report-path gitleaks-report.json
# Or using TruffleHog
trufflehog filesystem . --only-verifiedIf you do not have secret scanners installed, search manually for high-risk patterns:
# API key patterns
grep -rn "api_key\|apikey\|API_KEY" --include="*.ts" --include="*.tsx" --include="*.js" .
# Secret patterns
grep -rn "secret\|SECRET" --include="*.ts" --include="*.tsx" . | head -30
# Password patterns
grep -rn "password\|PASSWORD" --include="*.ts" --include="*.tsx" . | head -20
# Connection string patterns
grep -rn "postgres://\|mysql://\|mongodb://" . 2>/dev/nullDocument your findings
Create an inventory. For each finding, record:
| File/Pattern | Type | Example Content | Risk Level |
|---|---|---|---|
Risk levels:
- Critical: Credentials, encryption keys, connection strings with passwords
- High: API keys, tokens, personally identifiable information
- Medium: Internal URLs, service names, non-secret configuration
- Low: Example/placeholder values, documentation
Aim for 10-15 findings before proceeding.
Expected findings
A decent audit of this repository usually turns up:
Environment variable declarations:
- Database URLs (
DATABASE_URL) - NextAuth secrets (
NEXTAUTH_SECRET) - Stripe keys (
STRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET) - OAuth credentials (GitHub, Google)
- SMTP configuration (
SMTP_PASSWORD) - Svix webhook secrets (
SVIX_API_KEY)
Authentication patterns:
- JWT token handling in auth modules
- Session management configuration
- SAML/SSO setup requiring private keys
Infrastructure:
- Prisma database schema (reveals data models)
- Docker configs that reference environment variables
- GitHub Actions workflows that reference secrets
Phase 2: Data classification
Map your findings to the four-tier classification model from section 7.5.
Classification exercise
Assign a classification to each finding from Phase 1:
| Finding | Classification | Rationale |
|---|---|---|
| DATABASE_URL | Restricted | Contains credentials, direct database access |
| NEXTAUTH_SECRET | Restricted | Cryptographic secret, session integrity |
| STRIPE_SECRET_KEY | Restricted | Payment processing credentials |
| GITHUB_CLIENT_ID | Confidential | OAuth configuration, limited exposure risk |
| APP_URL | Internal | Application URL, no secrets |
| README.md | Public | Documentation, intended for sharing |
Work through your whole inventory. The edge cases are where it gets interesting:
- What about
.env.example? No secrets, but reveals what secrets exist. - What about Prisma schema files? No credentials, but reveals data models.
- What about test fixtures with fake API keys?
Classification decisions
Write down your reasoning for the non-obvious calls. These become precedents:
Example decision record:
Finding:
prisma/schema.prismaClassification: Internal Rationale: Has database schema but no credentials. Reveals data model, which could inform attacks but does not directly expose anything sensitive. Internal keeps it off public endpoints while letting the dev team work with it.
Create 3-5 records for your trickiest classification calls.
The high-watermark problem
This repository mixes sensitivity levels.
The /lib directory has both authentication logic (Confidential) and utility functions (Internal).
The /pages/api directory handles public endpoints and Stripe webhooks in the same folder.
How do you classify the repository as a whole?
Three options:
- Repository-level: Everything gets the highest tier (Restricted)
- Directory-level: Different paths get different classifications
- File-level: Classify individual files
Pick one and explain why.
Phase 3: Tool configuration
Turn your classification into actual tool settings.
Claude Code permissions.deny
Create a .claude/settings.json file that blocks access to sensitive files:
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./.env.local)",
"Read(./.env.production)",
"Edit(./.env*)",
"Write(./.env*)"
]
}
}Expand this based on your inventory. Think about:
- Environment files in other locations
- Certificate and key files if any exist
- Test fixtures with credential patterns
- Config files with sensitive defaults
Complete the deny list:
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Edit(./.env*)",
"Write(./.env*)"
// Add your patterns here based on Phase 1 findings
]
}
}permissions.deny blocks the Read tool but not Bash.
Someone (or some agent) could still run cat .env.
If that is in your threat model, configure hooks or restrict Bash too.
GitHub Copilot content exclusion
If your organization also uses GitHub Copilot, write the equivalent exclusion patterns:
# Organization or repository settings
"*":
- "**/.env"
- "**/.env.*"
- "**/secrets/**"
# Add patterns from your inventoryRemember from section 7.4: content exclusion does not apply to Copilot's agentic features. Copilot Chat and Agent mode ignore these patterns.
Pre-commit hook configuration
Create or update .pre-commit-config.yaml:
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.29.1
hooks:
- id: gitleaksIf Gitleaks is available, test the configuration:
# Install pre-commit if needed
pip install pre-commit
# Install hooks
pre-commit install
# Test against repository
pre-commit run gitleaks --all-filesWrite down any findings from the pre-commit scan that you missed manually.
Phase 4: Policy documentation
Write a short AI tool policy for this project. Make it practical. A developer joining the team should be able to read it and know what to do.
Policy template
Complete this template based on your audit:
# AI Coding Tool Policy - SaaS Starter Kit
## Approved Tools
- [ ] Claude Code (Enterprise tier required)
- [ ] Codex CLI
- [ ] GitHub Copilot Business
## Data Handling
### Files AI tools may access freely:
- [List directories/patterns classified as Public or Internal]
### Files requiring caution (Confidential):
- [List directories/patterns classified as Confidential]
### Files AI tools must not access (Restricted):
- [List directories/patterns classified as Restricted]
## Required Configurations
Before using AI coding tools on this project:
1. Install pre-commit hooks: `pre-commit install`
2. Configure Claude Code: Copy `.claude/settings.json` from repository
3. Verify exclusions: Run `claude code --check-permissions`
## Code Review Requirements
All AI-generated code requires:
- [ ] Human review before merge
- [ ] Security scanning via CI pipeline
- [ ] Verification that no secrets were included
## Exception Process
To use AI tools with files in the restricted category:
1. [Document your exception process]Debrief
How did your audit go?
| Question | Your Answer |
|---|---|
| How many sensitive files did manual review find? | |
| How many more did automated scanning catch? | |
| What was the scariest finding? | |
| Did anything surprise you? |
Classification calls
- Which classifications were hard to make?
- Where did the four-tier model feel wrong or incomplete?
- How would you handle directories that mix sensitivity levels?
Configuration gaps
- Does your
permissions.denycover all Restricted findings? - What risks remain that no configuration can address?
- How would you test that the configuration actually works?
Would your policy work?
- Would a new developer understand it?
- What questions would they still have?
- How would you get the team to actually follow it?
What this exercise teaches
Audits are useful when they produce things you can actually use. This one produces three:
The inventory tells you what sensitive data exists. Without this, your policies are guesses.
The classification answers the question "can I use Claude Code with this file?" A developer should not have to think hard about it. They look at the classification, they have an answer.
The configuration makes policy automatic. Technical controls beat relying on people to remember.
The other benefit: you get faster at this. After auditing one SaaS application, the second goes quicker. The same patterns show up everywhere. OAuth secrets, payment credentials, database URLs. You learn to spot them.
Variations
Variation A: Different framework
Do the same audit on the NestJS Boilerplate (github.com/brocoders/nestjs-boilerplate). Compare patterns. Does a NestJS backend look different from a Next.js fullstack app? Where do secrets tend to hide in each?
Variation B: Let the agent help
Use Claude Code to help with the audit:
Review this repository for sensitive data patterns.
Identify files that should be excluded from AI tool access.
Focus on credentials, API keys, database connections, and PII.Compare what the agent found to your manual audit. Did it catch things you missed? Did it cry wolf on anything?
Variation C: Test the configuration
After completing the audit, actually use Claude Code with your configuration. Try to do tasks that would need Restricted files. Does the deny list actually block them?
Variation D: Your own codebase
Run this audit on something real from your organization. Legacy codebases usually have more accumulated secrets than new projects. Years of developers, years of shortcuts. How does the audit scale with repository age?
Success criteria
- Sensitive data inventory completed (10+ findings)
- Classification assigned to all findings
- Classification decision records documented (3+)
- Claude Code
permissions.denyconfiguration created - Pre-commit hook configuration created
- AI tool policy draft completed
- Analysis section completed
Deliverables
When you are done, you should have:
- Inventory document listing sensitive files and patterns
- Classification mapping with a tier for each finding
.claude/settings.jsonwith deny rules.pre-commit-config.yamlwith secret scanning- Policy document for this project
These are templates. When you audit real projects, you produce the same artifacts but customized for each codebase. That is how secure AI tool adoption actually works.