Top 10 Things We Find in Every Penetration Test

Based on aggregate data from hundreds of penetration tests, Sherlock Forensics identifies the 10 most common vulnerabilities: default credentials (74% of engagements), missing rate limiting (81%), exposed internal services (68%), SQL injection (52%), cross-site scripting (63%), outdated software (77%), exposed .env files (58%), missing HTTPS (43%), broken access controls (71%) and absent security logging (84%). Penetration tests at Sherlock Forensics start at $1,500 CAD for quick audits and $5,000 CAD for standard external assessments.

The Vulnerabilities That Never Go Away

After hundreds of penetration tests across startups, mid-market companies and enterprise organizations, patterns emerge. The same vulnerabilities appear again and again, regardless of industry, team size or technology stack. Some are trivial to exploit. All are preventable.

This list is based on aggregate data from Sherlock Forensics engagements. For each finding, we cover what it is, how we exploit it, how common it is, its typical severity and how to fix it.

1. Default or Weak Admin Credentials

Found in: 74% of engagements
Severity: Critical
Exploitability: Trivial

What it is: Admin panels, database interfaces, CMS dashboards, cloud consoles and internal tools protected by default or easily guessable credentials. "admin/admin", "admin/password", "root/root" and company-name-based passwords are the most common.

How we exploit it: We maintain a custom wordlist built from thousands of engagements. We try default credentials for every technology we identify during reconnaissance. Most default logins take under 30 seconds to compromise. For weak passwords, targeted brute-force attacks with company-specific terms usually succeed within minutes.

How to fix it: Enforce strong, unique passwords on every admin interface. Use a password manager. Enable multi-factor authentication on all administrative accounts. Remove or restrict access to default admin panels. Change all default credentials immediately after deployment.

2. Missing Rate Limiting on Login Endpoints

Found in: 81% of engagements
Severity: High
Exploitability: Easy

What it is: Login forms, API authentication endpoints and password reset functions that accept unlimited attempts without throttling, lockout or CAPTCHA.

How we exploit it: Without rate limiting, we can attempt thousands of password combinations per minute. We use credential stuffing attacks with leaked password databases, brute-force attacks with targeted wordlists and password spraying across multiple accounts simultaneously. A login endpoint without rate limiting is functionally equivalent to handing out the password list and asking attackers to try each one.

How to fix it: Implement progressive rate limiting (increasing delays after failed attempts). Lock accounts after 5-10 failed attempts. Add CAPTCHA after 3 failed attempts. Monitor and alert on brute-force patterns. Use account lockout notifications to warn users of unauthorized access attempts.

3. Exposed Internal Services

Found in: 68% of engagements
Severity: High to Critical
Exploitability: Easy

What it is: Admin panels, debug endpoints, database management interfaces, monitoring dashboards, staging environments and internal APIs accessible from the public internet. Common examples include phpMyAdmin, Adminer, Laravel Telescope, Django Debug Toolbar, Grafana, Kibana and exposed Swagger/OpenAPI documentation.

How we exploit it: We discover exposed services through directory brute-forcing, subdomain enumeration and port scanning. Once found, these services often have weak authentication or none at all. A publicly accessible database management interface with default credentials gives us full database access. An exposed debug endpoint reveals application internals, environment variables and stack traces with file paths.

How to fix it: Restrict administrative interfaces to internal networks or VPN only. Use firewall rules to block public access to management ports. Remove debug toolbars and development endpoints from production deployments. Audit your external attack surface regularly to catch newly exposed services.

4. SQL Injection in Search or Filter Parameters

Found in: 52% of engagements
Severity: Critical
Exploitability: Moderate

What it is: User input from search fields, filter parameters, sorting options and URL parameters inserted directly into SQL queries without parameterization or sanitization. This allows attackers to modify the database query and extract, modify or delete data.

How we exploit it: We test every input field and URL parameter for SQL injection using manual techniques and tools like sqlmap. A single injectable parameter can give us full access to the database: user credentials, personal information, payment records and application secrets. In many cases, SQL injection also enables reading files from the server filesystem or executing operating system commands.

How to fix it: Use parameterized queries (prepared statements) for all database interactions. Never concatenate user input into SQL strings. Use an ORM that handles parameterization automatically. Implement input validation as a defense-in-depth measure, but never rely on it as the primary defense against injection.

5. Cross-Site Scripting in User-Generated Content

Found in: 63% of engagements
Severity: Medium to High
Exploitability: Moderate

What it is: User-supplied content (comments, profile fields, messages, form inputs) rendered in the browser without proper encoding or sanitization, allowing injection of malicious JavaScript. This includes stored XSS (persisted in the database and executed for every user who views the content), reflected XSS (returned in the response from a crafted URL) and DOM-based XSS (executed through client-side JavaScript manipulation).

How we exploit it: We inject JavaScript payloads through every user-controllable input. Successful XSS allows us to steal session cookies (enabling account takeover), redirect users to phishing pages, modify page content, capture keystrokes and perform actions as the victim. Stored XSS in a comment field means every user who views that page is compromised automatically.

How to fix it: Encode all user output using context-appropriate encoding (HTML encoding for HTML content, JavaScript encoding for script contexts, URL encoding for URLs). Use Content Security Policy (CSP) headers to restrict script execution. Use modern frameworks that auto-encode output by default (React, Vue, Angular). Never use innerHTML or dangerouslySetInnerHTML with user-controlled data.

6. Outdated Software with Known CVEs

Found in: 77% of engagements
Severity: Variable (Low to Critical)
Exploitability: Often trivial (public exploits available)

What it is: Web servers, frameworks, libraries, CMS platforms, plugins and runtime environments running versions with known, published vulnerabilities. Public exploit code is often available on GitHub or Exploit-DB, making exploitation trivial.

How we exploit it: We fingerprint every technology in your stack and check version numbers against CVE databases. For critical vulnerabilities with public exploits, exploitation is often a single command. Outdated WordPress plugins, unpatched Apache Struts, old Node.js versions with prototype pollution and vulnerable jQuery versions are among the most common targets.

How to fix it: Implement a patch management process. Subscribe to security advisories for every technology in your stack. Use automated dependency scanning tools (Dependabot, Snyk, Renovate) to catch outdated packages. Prioritize patches for internet-facing components. Maintain an inventory of all software versions in your infrastructure.

7. Exposed .env or Config Files with API Keys

Found in: 58% of engagements
Severity: Critical
Exploitability: Trivial

What it is: Environment files (.env), configuration files (config.php, settings.py, application.yml), backup files and Git repositories accessible from the public internet. These files frequently contain database credentials, API keys for payment processors (Stripe, PayPal), cloud provider credentials (AWS, GCP, Azure), email service credentials and encryption keys.

How we exploit it: We request common configuration file paths during reconnaissance: /.env, /.git/config, /config.php.bak, /wp-config.php.old and similar. When found, these files provide immediate access to databases, third-party services and cloud infrastructure. An exposed Stripe secret key means we can access payment data, issue refunds and create charges. Exposed AWS credentials can give us access to the entire cloud account.

How to fix it: Configure your web server to deny access to dotfiles and backup files. Move sensitive configuration outside the web root. Use environment variables instead of configuration files where possible. Add .env and config files to .gitignore before the first commit. Audit your web-accessible files regularly. Rotate any credentials that may have been exposed.

8. Missing HTTPS or Mixed Content

Found in: 43% of engagements
Severity: Medium
Exploitability: Moderate (requires network position)

What it is: Pages served over HTTP instead of HTTPS, HTTPS pages that load resources (scripts, stylesheets, images, API calls) over HTTP, missing HSTS headers, or HTTPS configured with weak cipher suites. Mixed content allows attackers on the same network to intercept and modify traffic.

How we exploit it: On shared networks (coffee shops, hotels, airports, corporate WiFi), we intercept HTTP traffic to capture credentials, session tokens and personal data. Mixed content on HTTPS pages allows us to inject malicious scripts through the unencrypted resources. Missing HSTS means users can be downgraded from HTTPS to HTTP through SSL stripping attacks.

How to fix it: Enforce HTTPS everywhere with automatic HTTP-to-HTTPS redirects. Enable HSTS with a long max-age (at minimum one year). Audit all pages for mixed content and update all resource URLs to HTTPS. Use modern TLS configurations (TLS 1.2+ with strong cipher suites). Consider HSTS preloading for maximum protection.

9. Broken Access Controls (IDOR)

Found in: 71% of engagements
Severity: High to Critical
Exploitability: Easy

What it is: Insecure Direct Object References (IDOR) and broken authorization checks where changing an ID, filename or parameter in a request gives access to another user's data or functions. The application verifies you are authenticated but does not verify you are authorized to access the specific resource you requested.

How we exploit it: We create two test accounts and systematically check whether user A can access user B's resources by modifying IDs in URLs, API parameters and request bodies. Common examples: changing /api/users/123/profile to /api/users/124/profile, modifying an order ID to view another customer's order, changing a document ID to download another user's files. In many applications, admin functions are simply hidden from the UI but still accessible if you know the URL.

How to fix it: Implement server-side authorization checks on every request. Never rely on hiding UI elements as a security control. Verify that the authenticated user owns or is authorized to access every resource they request. Use indirect references (random UUIDs instead of sequential integers) as a defense-in-depth measure. Implement automated authorization testing in your CI/CD pipeline.

10. No Security Logging or Monitoring

Found in: 84% of engagements
Severity: Medium (enables all other attacks)
Exploitability: N/A (it is the absence of a control)

What it is: Applications with no logging of authentication events, no monitoring of failed login attempts, no alerts for suspicious activity, no audit trail for administrative actions and no ability to detect or investigate a breach after it occurs. This is the most common finding across all engagements because it is the control most teams skip entirely.

How this helps attackers: Without logging, attackers operate with impunity. Brute-force attacks generate thousands of failed logins that nobody sees. Data exfiltration goes unnoticed for months. When a breach is eventually discovered, there is no forensic evidence to determine what was accessed, when or by whom. The average time to detect a breach without proper monitoring exceeds 200 days.

How to fix it: Log all authentication events (successful and failed logins, password resets, MFA challenges). Log all authorization failures. Log administrative actions. Monitor logs for anomalous patterns (brute-force attempts, unusual geographic access, privilege escalation). Set up real-time alerts for critical events. Retain logs for at minimum 90 days. Test your monitoring by simulating an attack and verifying detection.

How Many of These Apply to Your Application?

If you are honest with yourself, your application probably has at least three of these issues. Most applications we test have five or more. The question is not whether these vulnerabilities exist in your application. The question is whether you find them before an attacker does.

A penetration test from Sherlock Forensics covers all 10 of these categories and more. Quick audits start at $1,500 CAD with results in 3-5 business days. Standard external pentests start at $5,000 CAD. Every engagement includes a detailed report with severity ratings, proof-of-concept evidence and step-by-step remediation guidance. Order online or call 604.229.1994.

Frequently Asked Questions

What do penetration testers find?

The most common findings include default or weak credentials, missing rate limiting, exposed internal services, SQL injection, cross-site scripting, outdated software with known CVEs, exposed configuration files with API keys, missing HTTPS, broken access controls and absent security logging. Sherlock Forensics quick audits starting at $1,500 CAD test for all of these and more.

What are the most common security vulnerabilities?

Based on aggregate data from Sherlock Forensics penetration tests, broken access controls (71%), missing rate limiting (81%), absent security logging (84%) and outdated software (77%) are the most prevalent. These findings align with the OWASP Top 10 and appear across organizations of all sizes and industries.

How do hackers get into websites?

The most common attack paths are weak or default admin credentials, SQL injection through search and filter fields, exposed configuration files containing database passwords and API keys, outdated software with publicly available exploit code and broken access controls that let attackers view other users' data. A penetration test from Sherlock Forensics identifies these attack paths before real attackers exploit them.