
How to Pentest Your Own Web App: A Developer's Guide to Finding Vulnerabilities
How to Pentest Your Own Web App: A Developer's Guide to Finding Vulnerabilities
Most developers know their applications have security issues. The problem is not awareness — it is knowing where to start. Professional penetration testing costs $5,000 to $50,000 and takes weeks. Bug bounty programs require your app to already be in production. Vulnerability scanners generate hundreds of low-confidence findings that take days to triage.
What if you could test your own application's security yourself, using the same methodology professional pentesters use, before shipping it to users?
This guide walks you through a practical approach to pentesting your own web app. It is not a replacement for professional testing on high-value targets, but it will catch the vulnerabilities that actually get exploited in the real world.
What Pentesting Actually Is
Before we get into the how, let's clear up what pentesting is and is not.
Penetration testing is the practice of simulating real attacks against a system to find exploitable vulnerabilities. A pentester thinks like an attacker: they look at your application from the outside, identify weak points, and attempt to exploit them to prove the impact.
Vulnerability scanning is automated tooling that checks for known vulnerabilities against a database of signatures. Scanners are fast and broad but shallow. They tell you "this header is missing" but not "here is how an attacker chains three findings together to steal your database."
Bug bounty programs invite external researchers to find vulnerabilities in exchange for rewards. These are valuable but require a mature security posture — you do not want strangers finding critical issues in a product that has never had a basic security review.
Pentesting sits in between: deeper than scanning, more targeted than bug bounty, and focused on proving real-world exploitability.
The Pentesting Mindset for Developers
The hardest part of pentesting your own application is switching from builder mindset to breaker mindset. As a developer, you think about how things should work. As a pentester, you think about how things can be misused.
Some principles to internalize:
Test the boundaries, not the happy path. Your app works correctly with valid input. What happens with empty strings, extremely long strings, negative numbers, special characters, null bytes, and Unicode edge cases?
Think about who, not what. For every feature, ask: can User A access User B's data? Can a free user access paid features? Can an unauthenticated user access authenticated endpoints?
Follow the data. Trace how user input flows from the browser through your API to the database and back. At each step, ask: is this input trusted? Is it validated? Is it escaped?
Check what is visible. Your API might return more data than the UI displays. Your JavaScript bundles might contain secrets. Your error messages might reveal internal details.
Assume nothing is hidden. Client-side checks, hidden form fields, obfuscated URLs, and disabled buttons are not security controls. If the browser can see it or send it, an attacker can too.
Phase 1: Reconnaissance
Professional pentesters spend significant time on recon before attempting any exploits. For your own app, you already have insider knowledge, but it is still worth doing a systematic review from the outside.
Map Your Attack Surface
Create a list of every entry point into your application:
- All URL paths — including ones not linked in the navigation
- All API endpoints — including ones only used internally
- All form inputs — login, signup, search, file upload, settings
- All query parameters and URL segments — anything that changes what data is returned
- All cookies and headers your application uses
- All third-party integrations — OAuth providers, payment processors, analytics
Check What Is Publicly Visible
# Check DNS records for subdomains
dig +short example.com ANY
nslookup -type=any example.com
# Use subfinder for subdomain enumeration
subfinder -d example.com -silent
# Check what technologies the app uses (headers, meta tags, scripts)
curl -s -I https://example.com | head -20
# Look for common exposed paths
curl -s -o /dev/null -w "%{http_code}" https://example.com/.env
curl -s -o /dev/null -w "%{http_code}" https://example.com/.git/config
curl -s -o /dev/null -w "%{http_code}" https://example.com/api/docs
curl -s -o /dev/null -w "%{http_code}" https://example.com/graphql
curl -s -o /dev/null -w "%{http_code}" https://example.com/_next/data
View Your Source From the Outside
Open your deployed application in an incognito browser window. View the page source and search for:
- API keys, tokens, or credentials
- Internal URLs or IP addresses
- Comments containing sensitive information
- Hidden form fields with interesting values
- JavaScript source maps that expose your source code
# Download and search JavaScript bundles
curl -s https://example.com | grep -oP 'src="[^"]*\.js"' | head -20
# Then download each bundle and search for secrets
Phase 2: Testing Authentication
Authentication is the first gate an attacker encounters. If it is weak, everything behind it is exposed.
Test Login Security
Brute force resistance: Attempt 20-30 logins with wrong passwords in rapid succession. Does the application rate-limit, lock the account, show a CAPTCHA, or just keep accepting attempts?
# Quick brute force test with curl
for i in $(seq 1 30); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
-X POST https://example.com/api/auth/login \
-H "Content-Type: application/json" \
-d '{"email":"test@test.com","password":"wrong'$i'"}')
echo "Attempt $i: $STATUS"
done
# If all 30 return 401 (not 429), there is no rate limiting
Account enumeration: Try logging in with a valid email and wrong password, then with a nonexistent email. If the error messages are different ("Invalid password" vs "User not found"), an attacker can enumerate valid accounts.
Password requirements: Can you set a 1-character password? Can you use "password" or "123456"? Weak password policies make brute force attacks trivially easy.
Test Session Management
Session token quality: Log in and inspect the session cookie or token. Is it long and random, or is it a short, predictable value? JWTs should use a strong secret and short expiration.
Session fixation: Note your session token before logging in. Log in and check if the token changed. If it did not, an attacker who knows a pre-authentication session ID automatically gets authenticated access.
Session expiration: Log in, copy the session token, wait (or manually advance time if testing locally), and try using it again. Sessions that never expire are stolen sessions that never stop working.
Concurrent sessions: Log in from two different browsers. Does the application allow it? Can you see and revoke other sessions? Is there a maximum session limit?
Test Password Reset
Token predictability: Request multiple password resets and compare the tokens. Are they random, or is there a pattern?
Token expiration: Request a reset, wait an hour, then try to use it. A reset token that works after 24 hours is a risk.
Token reuse: Use a reset token successfully, then try to use it again. Single-use enforcement prevents replay attacks.
User enumeration: Request a password reset for a nonexistent email. If the response is different from a valid email, it leaks information about which accounts exist.
Phase 3: Testing Authorization
Authorization vulnerabilities are the most common and most dangerous issues we find at PreBreach. The test is simple: can you access resources that do not belong to you?
Insecure Direct Object References (IDOR)
This is the single most exploitable vulnerability in web applications. The test:
- Log in as User A and access a resource (profile, document, invoice) — note the URL or ID
- Log in as User B (or log out entirely)
- Try to access User A's resource using the same URL or ID
# As User A, access your profile
curl -H "Authorization: Bearer TOKEN_A" https://example.com/api/users/123
# As User B, try to access User A's profile
curl -H "Authorization: Bearer TOKEN_B" https://example.com/api/users/123
# Without authentication, try the same
curl https://example.com/api/users/123
Test this on every endpoint that takes an ID parameter: /api/users/:id, /api/posts/:id, /api/invoices/:id, /api/files/:id. If any of these return data for a user who should not have access, you have an IDOR vulnerability.
Privilege Escalation
Vertical escalation: Can a regular user access admin functionality?
# As a regular user, try admin endpoints
curl -H "Authorization: Bearer REGULAR_USER_TOKEN" \
https://example.com/api/admin/users
curl -H "Authorization: Bearer REGULAR_USER_TOKEN" \
https://example.com/api/admin/settings
Horizontal escalation: Can User A modify User B's resources?
# As User A, try to update User B's profile
curl -X PATCH \
-H "Authorization: Bearer TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"name":"Hacked"}' \
https://example.com/api/users/USER_B_ID
Parameter manipulation: Can you escalate your role by modifying your own profile?
# Try to set your own role to admin
curl -X PATCH \
-H "Authorization: Bearer TOKEN_A" \
-H "Content-Type: application/json" \
-d '{"role":"admin"}' \
https://example.com/api/users/YOUR_ID
Feature-Level Access Control
If your app has tiers (free, pro, enterprise), test whether free users can access paid features:
# As a free user, try to access paid endpoints
curl -H "Authorization: Bearer FREE_USER_TOKEN" \
https://example.com/api/pro/export
curl -H "Authorization: Bearer FREE_USER_TOKEN" \
https://example.com/api/pro/advanced-analytics
Phase 4: Testing for Injection
Injection vulnerabilities occur when user input is interpreted as code or commands.
SQL/NoSQL Injection
Test every input field and API parameter with injection payloads:
' OR '1'='1
'; DROP TABLE users; --
{"$gt": ""}
{"$ne": null}
Focus on:
- Search fields
- Filter parameters
- Sort parameters
- Login forms (email and password fields)
- Any field that likely maps to a database query
If any of these inputs cause unexpected behavior (returning all records, errors with SQL syntax details, or different response times), there may be an injection vulnerability.
Cross-Site Scripting (XSS)
Test every place where user input is displayed back to the page:
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
"><svg onload=alert('XSS')>
javascript:alert('XSS')
Focus on:
- User profile names and bios
- Comment and message fields
- Search queries displayed in "Showing results for..."
- URL parameters reflected in the page
- Error messages that include user input
Server-Side Request Forgery (SSRF)
If your application fetches URLs provided by users (avatars, link previews, webhooks, imports), test whether it can be tricked into accessing internal resources:
http://localhost:3000/api/admin
http://127.0.0.1:5432
http://169.254.169.254/latest/meta-data/ (AWS metadata)
http://metadata.google.internal/ (GCP metadata)
Phase 5: Checking Configuration
Configuration issues are often low-effort, high-impact findings.
Security Headers
# Check all security headers at once
curl -s -I https://example.com | grep -i \
"strict-transport-security\|content-security-policy\|x-frame-options\|x-content-type-options\|referrer-policy\|permissions-policy"
What you should see:
Strict-Transport-Security: max-age=63072000; includeSubDomainsX-Frame-Options: DENYorSAMEORIGINX-Content-Type-Options: nosniffReferrer-Policy: strict-origin-when-cross-originContent-Security-Policy: ...(some form of CSP)
CORS Configuration
# Test if CORS allows any origin
curl -s -I -H "Origin: https://evil.com" https://example.com/api/test \
| grep -i "access-control-allow-origin"
# If the response includes "https://evil.com" or "*", CORS is misconfigured
Cookie Security
Inspect cookies in your browser's developer tools. Check for:
Secureflag (only sent over HTTPS)HttpOnlyflag (not accessible to JavaScript)SameSiteattribute (StrictorLax, notNonewithout good reason)- Reasonable expiration time
# Check cookie attributes
curl -s -I -c - https://example.com/api/auth/login \
-X POST -d '{"email":"test@test.com","password":"password"}' \
| grep -i "set-cookie"
Information Leakage
Check for exposed debug information:
# Common information disclosure endpoints
curl -s https://example.com/api/health
curl -s https://example.com/api/debug
curl -s https://example.com/api/info
curl -s https://example.com/.env
curl -s https://example.com/phpinfo.php
curl -s https://example.com/server-status
curl -s https://example.com/api/graphql?query=\{__schema\{types\{name\}\}\}
# Check if source maps are exposed
curl -s -o /dev/null -w "%{http_code}" \
https://example.com/_next/static/chunks/main.js.map
Free Tools Overview
You do not need expensive commercial tools to do effective security testing. Here are the free tools that cover the most ground.
OWASP ZAP
The most comprehensive free web security testing tool. ZAP can:
- Proxy your browser traffic and record all requests
- Automatically scan for common vulnerabilities
- Fuzz parameters with attack payloads
- Analyze API responses for information leakage
# Run ZAP in headless mode for automated scanning
docker run -t ghcr.io/zaproxy/zaproxy:stable zap-baseline.py \
-t https://example.com
ZAP's automated scan catches missing headers, cookie issues, and some injection vulnerabilities. For deeper testing, use it as an intercepting proxy and manually test the high-value endpoints.
Nuclei
A fast, template-based vulnerability scanner that is excellent for checking known vulnerability patterns:
# Install nuclei
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
# Run with default templates
nuclei -u https://example.com
# Run specific template categories
nuclei -u https://example.com -tags cve,misconfig,exposure
# Run against multiple URLs
echo "https://example.com" | nuclei -l -
Nuclei is what PreBreach uses as one component of its scanning infrastructure. Our 24 custom templates extend Nuclei's capabilities for modern stacks like Next.js, Supabase, Firebase, Vercel, and Clerk.
nmap
For infrastructure-level scanning, nmap reveals open ports and services:
# Scan common web ports
nmap -sV -p 80,443,8080,8443,3000,5000 example.com
# Scan for all open ports (slower)
nmap -sV -p- example.com
# Check for common web vulnerabilities
nmap --script=http-enum,http-headers,http-methods example.com
Browser Developer Tools
Your browser's built-in tools are surprisingly powerful for security testing:
- Network tab: Inspect every request and response. Look for sensitive data in API responses.
- Application tab: Review cookies, localStorage, sessionStorage for sensitive values.
- Console: Test JavaScript access to sensitive data.
- Sources tab: Search JavaScript bundles for hardcoded secrets.
Burp Suite Community Edition
The free version of Burp Suite provides an intercepting proxy and basic scanner. It is the industry standard for manual web security testing. The paid version adds automated scanning, but the free proxy and repeater are sufficient for manual testing.
When to Automate
Manual pentesting is thorough but time-consuming. You should automate when:
- You ship frequently. If you deploy multiple times per week, manual testing on every release is not practical.
- You want consistent coverage. Human testers vary in their thoroughness. Automated testing checks the same things every time.
- You need to test at the speed of development. Modern CI/CD means changes go to production within hours. Security testing needs to keep up.
This is exactly why we built PreBreach. Our 8 AI agents powered by Claude Opus do not just run templates — they understand your application's architecture and test it the way a human pentester would, but at the speed of automation. The multi-model validation (GPT cross-checking Claude's findings) reduces false positives to near zero.
A PreBreach scan covers:
- Authentication and session management testing
- Authorization and IDOR testing across all endpoints
- Injection testing (SQL, NoSQL, XSS, SSRF)
- Configuration review (headers, CORS, cookies, TLS)
- Secret detection in client-side code
- Dependency vulnerability analysis
- Modern stack-specific checks (24 custom Nuclei templates)
The entire scan runs in 30-60 minutes with subscription plans from $29-$199/month.
When to Hire a Professional
DIY pentesting and automated tools cover a lot of ground, but there are situations where you need a human expert:
- Handling sensitive data at scale. If you process financial data, health records, or data subject to compliance requirements (SOC 2, HIPAA, PCI DSS), hire a professional.
- Before a major funding round. Investors increasingly ask about security posture. A professional pentest report demonstrates diligence.
- After a security incident. If you have been breached, you need an expert to assess the full scope and ensure the attacker's access has been completely removed.
- Complex business logic vulnerabilities. Some vulnerabilities are specific to your application's logic (pricing manipulation, workflow bypass, race conditions in transactions). These require human creativity to find.
- Compliance requirements. Some regulations and certifications require pentesting by an independent third party.
For most indie developers and early-stage startups, the combination of DIY testing (using this guide), automated scanning (using PreBreach), and a professional pentest before major milestones provides comprehensive coverage without breaking the budget.
Getting Started Today
You do not need to do everything in this guide in a single sitting. Start with the highest-impact tests:
-
Check for IDOR (Phase 3) — 30 minutes. This is the most commonly exploited vulnerability. Log in as two different users and try to access each other's data.
-
Check for exposed secrets (Phase 1 recon) — 15 minutes. View your page source and search for API keys. Check your JavaScript bundles.
-
Test your login security (Phase 2) — 20 minutes. Try 30 rapid login attempts. Check if error messages leak information.
-
Verify security headers (Phase 5) — 5 minutes. One curl command tells you if basic protections are in place.
-
Run an automated scan — 30-60 minutes (runs in background). Use OWASP ZAP, Nuclei, or PreBreach to catch what manual testing misses.
The goal is not perfection. The goal is to find and fix the critical vulnerabilities before someone else does. Every issue you find and fix yourself is an issue that an attacker cannot exploit against your users.
Start your first PreBreach scan and see what an AI-powered pentest finds in your application.
