ScreenshotNeo

BlogHow-to

How to Find Website Vulnerabilities With Security Testing

A practical, authorized workflow for finding website vulnerabilities, preserving evidence, and helping owners fix and retest security issues.

By the ScreenshotNeo team1 October 20269 min read

Direct answer: Find website vulnerabilities with an authorized, repeatable web application security test. First observe the application as a normal user, then validate security controls across the approved attack surface. Preserve evidence, assess impact, give the system owner a practical mitigation, and retest after the fix.

Only test systems, domains, accounts, APIs, and environments for which you have written permission. A vulnerability is a flaw or weakness in a system’s design, implementation, operation, or management that could be exploited to compromise security objectives. OWASP’s Web Security Testing Guide (WSTG) describes security testing as methodically validating and verifying application-security controls.

1. Establish authorization and scope before touching the site

Write down the permission, the owner, the dates, and the boundaries. This protects the owner and keeps testing from becoming an accidental outage or an unauthorized intrusion.

Scope item Record
Targets Exact domains, subdomains, IP ranges, API hosts, mobile endpoints, and environments
Accounts Test users, roles, tenant IDs, administrator access, and accounts that must not be touched
Methods Passive discovery, authenticated testing, rate limits, automated scanners, and manual checks
Timing Start and end time, maintenance windows, and an emergency contact
Prohibited actions Denial-of-service testing, destructive data changes, real-world email or payment actions, and out-of-scope hosts
Evidence handling Where requests, responses, screenshots, and secrets will be stored and when they will be deleted

Use a staging environment where possible. If production is in scope, use dedicated test accounts and harmless records. Stop and notify the owner if you encounter real customer data, a serious compromise, or instability.

2. Map the application passively

Begin with normal user journeys. Do not change state while building your map. Record pages, forms, redirects, API calls, cookies, roles, and error behavior.

  1. List public entry points: home pages, login and registration, password recovery, search, uploads, checkout, and contact forms.
  2. Use each approved role and note what it can see and do.
  3. Capture URLs, HTTP methods, parameters, request bodies, response codes, redirects, and content types.
  4. Identify client-side routes, API hosts, WebSocket endpoints, third-party integrations, and version clues.
  5. Record security-relevant behavior such as cache headers, cookie attributes, CORS responses, error pages, and authentication redirects.

Passive mapping matters because business logic is often visible only in the sequence of ordinary actions. It also gives you a baseline for later active checks.

A small passive inventory script

The following Python program fetches approved URLs without submitting forms. It records status, redirects, selected headers, and a hash of the response body so you can compare runs without storing page contents.

import hashlib
import json
import sys
from urllib.parse import urlparse

import requests

URLS = sys.argv[1:] or ["https://example.com/"]
for url in URLS:
    parsed = urlparse(url)
    if parsed.scheme not in {"http", "https"}:
        raise SystemExit(f"Unsupported URL: {url}")
    response = requests.get(url, timeout=20, allow_redirects=True)
    body_hash = hashlib.sha256(response.content).hexdigest()
    record = {
        "requested_url": url,
        "final_url": response.url,
        "status": response.status_code,
        "content_type": response.headers.get("content-type"),
        "server": response.headers.get("server"),
        "location": response.headers.get("location"),
        "set_cookie_present": "set-cookie" in response.headers,
        "body_sha256": body_hash,
    }
    print(json.dumps(record, sort_keys=True))

Run it only against URLs in your written scope:

python inventory.py https://staging.example.com/ https://staging.example.com/login

3. Validate the security controls

OWASP’s developer guidance groups core testing domains into configuration and deployment management, identity management, authentication, authorization, and session management. Expand the checks for the application’s APIs, workflows, data exposure, and deployment architecture.

Configuration and deployment

  • Check that debug pages, stack traces, directory listings, source maps, backups, and test consoles are disabled in production.
  • Review TLS behavior, security headers, cache rules, CORS policy, allowed HTTP methods, and default credentials.
  • Verify that secrets are not exposed in HTML, JavaScript bundles, logs, public repositories, or error responses.
  • Check administrative interfaces and monitoring endpoints for network restrictions and strong authentication.

Identity and authentication

  • Test registration, login, logout, password reset, email change, multi-factor enrollment, and account recovery as each approved role.
  • Check rate limiting and lockout behavior with a small, agreed request budget.
  • Confirm that session identifiers rotate after login and privilege changes, and that logout invalidates the server-side session.
  • Inspect cookies for Secure, HttpOnly, and appropriate SameSite settings.

Authorization and tenant isolation

  • For every role, attempt only the documented, harmless variations of an approved request.
  • Verify that changing an object identifier cannot expose another user’s record.
  • Check server-side enforcement for administrative routes; hiding a button in the browser is not authorization.
  • For multi-tenant systems, repeat the same workflow with two test tenants and confirm that identifiers, exports, search, and caches remain isolated.

Input handling and output encoding

  • Test validation at the server boundary for type, length, format, and allowed values.
  • Check that user-controlled data is encoded for its output context: HTML, attributes, JavaScript, URLs, and headers.
  • Use harmless marker values in approved fields and verify that they are stored, displayed, and logged safely.
  • Check file uploads for type validation, size limits, storage location, download authorization, and filename handling.

Sessions, APIs, and business workflows

  • Check CSRF protections on state-changing browser requests and verify origin or token validation where required.
  • Compare browser and direct API behavior; an API must enforce the same role and tenant rules as the UI.
  • Test replay, duplicate submission, ordering, and cancellation in workflows such as checkout, invitations, refunds, and password changes.
  • Confirm that sensitive data is minimized in responses and removed from logs, analytics, and client storage.

4. Capture reproducible evidence

Every finding should let the owner reproduce the behavior without guessing. Store the smallest useful evidence set and redact credentials, tokens, personal data, and secrets.

Field What to include
Title Short description with the affected control and location
Preconditions Role, account, tenant, setup, and required state
Location URL or API endpoint, method, parameter, and application version if known
Steps Numbered, minimal reproduction sequence using safe test data
Evidence Relevant request and response excerpts, timestamps, and a redacted screenshot when it clarifies the issue
Impact What a permitted or unauthorised user could read, change, or trigger
Remediation Specific server-side control, configuration change, or code change
Retest Exact check to repeat after the fix and the expected secure result

Rate severity using the owner’s chosen risk method. Explain likelihood and impact in plain language instead of relying on a score alone. A missing authorization check on a sensitive record, for example, deserves a different response from an informational header observation.

5. Turn findings into fixes and retest

  1. Discuss each finding with the system owner and confirm that the observed behavior is understood.
  2. Agree on an owner, remediation, and target date.
  3. After deployment, repeat the original steps with the same role and test data.
  4. Test nearby variants so the fix is enforced server-side rather than only in one UI path.
  5. Record the result as fixed, partially fixed, accepted risk, or still open, with new evidence.

6. Use screenshots as evidence without exposing users

A screenshot can make a visual issue reproducible, but it can also capture personal data, tokens, or a consent banner that obscures the relevant state. Redact sensitive values, use a test account, and keep captures in the approved evidence store. For repeatable visual checks, capture the same viewport, role, locale, and application state each time.

7. Or skip the browser setup

ScreenshotNeo is a website screenshot API and MCP server. It accepts one GET request and returns a PNG, JPEG, WebP, or PDF. Before capture it accepts cookie and consent banners and removes more than 60 known consent platforms, newsletter popups, and chat widgets; each step can be turned off. Bot checks or CAPTCHAs, blank pages, timeouts, failed loads, and cache hits are not billed, and the response identifies the result with X-Page-Verdict and X-Billed headers.

See the ScreenshotNeo documentation for all options. The same endpoint supports full-page and element captures, device presets or custom viewports, dark mode, retina scale, custom CSS and JavaScript, clicks, waits, request blocking, headers, cookies, user agents, authorization, timezone, geolocation, transparent backgrounds, resizing, caching, signed links, asynchronous jobs, webhooks, bulk capture, usage data, and PDF output.

cURL

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://staging.example.com/login \
  -o security-evidence.webp

Python

import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://staging.example.com/login"},
    timeout=90,
)
r.raise_for_status()
open("security-evidence.webp", "wb").write(r.content)
print(r.headers.get("X-Page-Verdict"), r.headers.get("X-Billed"))

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://staging.example.com/login' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot failed: ${res.status}`);
const data = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('security-evidence.webp', data);
console.log(res.headers.get('X-Page-Verdict'), res.headers.get('X-Billed'));

For AI-assisted review, its MCP server exposes take_screenshot, get_page_info, and capture_pdf to Claude, Cursor, and other MCP clients. You get 1,000 screenshots per month free with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

8. Troubleshooting common testing problems

Problem Likely cause Fix
You see a login page instead of the target route The route requires an authenticated session Use an approved test account, document the role, and capture the authenticated request through the permitted test setup.
A scanner reports many false positives It cannot understand business context or the application’s normal flow Confirm each result manually, remove duplicates, and attach a reproducible request and impact.
Requests trigger rate limits The test exceeded the agreed request budget Stop automated traffic, notify the owner, lower concurrency, and resume only within the written limit.
A finding disappears between runs State, feature flags, cache, or test data changed Record preconditions, reset to a known state, and repeat with a fresh test record.
Evidence contains sensitive data The test used a real account or an unredacted response Stop sharing it, restrict access, redact or delete according to the engagement plan, and repeat with synthetic data.
ScreenshotNeo returns a blank or blocked page The site served a bot check, failed to load, or timed out Inspect X-Page-Verdict and X-Billed; use an approved wait, headers, cookies, or user agent, and do not treat a blocked capture as application evidence.

9. Performance, reliability, and cost considerations

  • Keep passive discovery low-rate and cache your own inventory. Run active checks in small, observable batches.
  • Prefer deterministic test data and fixed roles so a retest compares the same behavior.
  • Separate evidence collection from destructive or state-changing actions; require an explicit owner-approved step for the latter.
  • For screenshot evidence, use a consistent viewport and wait condition. ScreenshotNeo supports selector waits, delays, network-idle waits, caching with a chosen TTL, asynchronous jobs, signed webhooks, and bulk capture of up to 100 URLs per call.
  • Estimate screenshot cost from the plan and whether captures are cache hits or clean billed shots. ScreenshotNeo’s Free plan includes 1,000 shots monthly without a card; Starter is $5 for 3,000, Growth $15 for 15,000, Pro $39 for 60,000, Scale $99 for 250,000, and Business $249 for 1,000,000. Yearly billing gives two months free, and every feature is included on every plan.

10. Short FAQ

Is vulnerability testing the same as a vulnerability scan?

No. A scanner can find candidates quickly, while a security test validates controls, understands business logic, proves impact safely, and gives the owner a remediation path.

Should testing start with OWASP Top 10?

Use OWASP guidance as a framework, then map it to the application’s actual roles, APIs, workflows, and deployment architecture. No checklist guarantees complete coverage.

Can I test a site I do not own if it is public?

No. Public availability is not permission. Obtain written authorization and scope before active testing.

What makes a finding actionable?

A clear precondition, exact location, safe reproduction, evidence, impact, recommended fix, and a retest procedure.

When should I use a screenshot in a report?

Use one when visual state explains the issue or proves a before-and-after result. Redact secrets and personal data, and retain the original only in the approved evidence store.

For the methodology and terminology, start with the OWASP Web Security Testing Guide and its Developer Guide. Then adapt the checks to the authorized system, preserve reproducible evidence, and retest every fix.