0 · Is Aegis right for you?
The most useful thing we can tell you is when the answer is no.
✓ Aegis is a good fit if…
- You have a web application or API and need it tested before go-live.
- A customer, investor or auditor is asking for a penetration test report (SOC 2, ISO 27001, a security questionnaire).
- You want authenticated testing — behind the login, where the real risk is — not just a surface scan.
- You run multi-tenant SaaS and need tenant isolation proven.
- You want results today, repeatably, without scheduling a consultancy.
- A $4,000–$15,000 engagement is out of proportion to your stage.
✗ Aegis is the wrong tool if…
- You need a human red team — creative chained exploits, novel zero-days, physical or social engineering. Hire a consultancy; we are not a substitute.
- You need a signed attestation from a certified assessor (some PCI DSS and government procurement paths require a qualified, independent human tester).
- Your priority is source-code and dependency scanning (SAST/SCA/containers). Aikido, Snyk and Semgrep do that well; we test the running application instead — many customers use both.
- You need network, infrastructure or cloud-configuration testing. We test applications over HTTP(S).
- You cannot prove domain ownership. No proof, no test — no exceptions.
- You want someone to fix the findings for you. We tell you precisely what and how; the change is yours to make.
| What you need | Best choice | Why |
|---|---|---|
| Audit-ready pentest report, fast & affordable | Aegis — $1,499 | Same automation category as a $4,000 AI pentest; a fraction of the price. |
| Broad code/dependency/container/cloud coverage | Aikido, Snyk | Genuinely broader platforms. We don't do SAST or SCA. |
| Continuous surface monitoring of many assets | Intruder, Detectify | Built for breadth of assets rather than depth per application. |
| Human-led red team / novel exploitation | A consultancy | Creativity is not automatable. Expect $10k+. |
| Business-logic & multi-tenant authorization depth | Aegis | Two-identity differential testing most scanners don't attempt. |
1 · How testing works, end to end
Five stages. Nothing runs until ownership is proven.
| Stage | What happens |
|---|---|
| 1. Ownership proof | You add a DNS TXT record. We resolve it against public DNS. No verification, no scan — there is no manual override. |
| 2. Rules of engagement | You confirm scope, rate limits, excluded paths, backup readiness and an emergency contact. Recorded with a timestamp as your authorisation. |
| 3. Discovery | We map the reachable surface — pages, endpoints, forms, parameters. For authenticated tiers we sign in first, so we see what real users see. |
| 4. Testing | Checks run inside enforced budgets: capped requests, limited concurrency, throttled rate. Every request is logged. |
| 5. Report | Findings with evidence, business impact and remediation — plus the controls we attacked and confirmed holding. |
2 · What each severity actually means
Severity is about consequence, not how alarming the name sounds.
| Severity | Meaning | Act within |
|---|---|---|
| Critical | Directly exploitable now, with serious consequence — full account takeover, mass data exposure, remote code execution. | Immediately. Before your next release. |
| High | Exploitable with modest effort, or exposes sensitive data to the wrong party. | Days. |
| Medium | Not exploitable alone, but removes a defensive layer or meaningfully helps an attacker. | This sprint. |
| Low | Defence-in-depth gap. Little standalone risk; compounds with others. | Backlog. |
| Info | No risk today. Worth knowing — often hygiene or drift. | When convenient. |
Severities interact. A reflected parameter (Low) plus a weak Content-Security-Policy (Medium) is materially worse than either alone: the CSP is what would have contained the reflection if it ever became injectable. We call out these combinations in the report.
3 · Transport & TLS
HTTP Strict-Transport-Security (HSTS) Low All tiers
We request your site over HTTPS and inspect the response for a Strict-Transport-Security header, checking max-age and whether subdomains are covered.
Missing: a visitor's first request — or one where an attacker strips TLS on a hostile network — can travel over plain HTTP, exposing the session cookie. Present: browsers refuse HTTP for your domain entirely after the first visit.
- Add the header at your edge or origin:
Strict-Transport-Security: max-age=31536000; includeSubDomains
- Confirm every subdomain is HTTPS-ready before adding
includeSubDomains— it applies to all of them. - Once stable, consider submitting to the browser preload list.
4 · Security headers
X-Content-Type-Options, Referrer-Policy, Permissions-Policy Low All tiers
We read response headers across several pages — not just the homepage, since headers are often applied inconsistently by route.
No nosniff: a browser may guess a file's type and execute an upload as script. No Referrer-Policy: full URLs (which may carry tokens or IDs) leak to third-party sites. No Permissions-Policy: embedded content can request camera, microphone or location.
- Set all three globally at the edge so no route can miss them:
X-Content-Type-Options: nosniff Referrer-Policy: strict-origin-when-cross-origin Permissions-Policy: camera=(), microphone=(), geolocation=()
- Re-scan to confirm they appear on API responses and error pages too.
5 · Cookies & sessions
Cookie security attributes Medium All tiers
We inspect every Set-Cookie for Secure, HttpOnly and SameSite, and identify which cookie carries the session.
No Secure: the cookie can be sent over plain HTTP and captured. No HttpOnly: any JavaScript — including injected script — can read your session token. No SameSite: the browser attaches the cookie to cross-site requests, enabling CSRF.
- Set all three on the session cookie:
Secure; HttpOnly; SameSite=Lax(useStrictif you have no cross-site flows). - If your framework has an HTTPS flag (e.g. an
APP_HTTPS=1style setting), ensure it is on in production — cookies are often only markedSecurewhen it is. - Rotate the session-signing secret if it has ever been shared across installs.
6 · Content-Security-Policy & CORS
Content-Security-Policy strength Medium All tiers
We parse your CSP and evaluate the script-related directives, flagging unsafe-inline, unsafe-eval, overly broad wildcards and a missing frame-ancestors.
CSP is the seatbelt for cross-site scripting. A missing or permissive policy doesn't create a vulnerability — it removes the control that would have contained one. With unsafe-inline, an injected <script> executes exactly as the attacker intended.
- Start in report-only mode to find breakage without downtime:
Content-Security-Policy-Report-Only. - Remove
unsafe-inlineby moving inline scripts to files or adding a per-request nonce. - Remove
unsafe-eval— usually a library doing string-to-code; most have a CSP-safe build. - Add
frame-ancestors 'none'(or your allowed embedders) to stop clickjacking. - Enforce, then re-scan. Confirm your CDN doesn't strip or replace the header.
CORS configuration High if permissive All tiers
We send cross-origin and preflight requests with varied Origin values to see which are accepted, and whether credentials are permitted.
The dangerous combination is reflecting any origin and allowing credentials — that lets any website read authenticated responses on behalf of a logged-in visitor. Access-Control-Allow-Origin: * without credentials is usually fine for public data.
- Replace origin reflection with a strict allow-list of known origins.
- Never combine a wildcard (or reflected) origin with
Access-Control-Allow-Credentials: true. - Restrict allowed methods and headers to what the client genuinely uses.
7 · Attack-surface discovery
Endpoint inventory & API spec drift Info All tiers
We crawl the reachable application — authenticated, on paid tiers — inventorying URLs, methods, parameters and forms, then compare against your OpenAPI specification if you provide one.
Endpoints live in production that aren't in your spec. Undocumented routes escape design review and access-control decisions — historically a common source of forgotten admin and debug endpoints.
- Review each undocumented route: is it intentional?
- Remove debug, test and legacy endpoints from production.
- Document the rest, including their authentication requirements.
8 · Injection — SQLi, XSS, SSTI, command, path, SSRF, XXE & open redirect
SQL injection (boolean-based) Critical if found Go-Live
We submit pairs of logically true and false conditions to each parameter and compare responses. A page that changes between always-true and always-false is evaluating input as SQL. We use inert boolean logic — never data-modifying or destructive payloads.
An attacker can read, and often modify, your database directly — every customer record, password hash and payment detail. This is as serious as application security gets.
- Use parameterised queries (prepared statements) everywhere. Never build SQL by string concatenation.
- In an ORM, avoid raw-SQL escape hatches with interpolated values.
- Validate and type-check input, but treat that as secondary — parameterisation is the actual fix.
- Give the application's database user the least privilege it needs.
- Assume compromise: review logs, and rotate credentials if exploitation is plausible.
Cross-site scripting (inert canary) High if found Go-Live
We submit a harmless unique marker and check whether it is reflected into the response, and in what context — HTML body, attribute, or JavaScript. We never inject working exploit code.
Reflected and unescaped in an executable context: an attacker can run JavaScript as your users — stealing sessions, altering pages, exfiltrating data. Reflected but correctly escaped: not a vulnerability, but a place to keep encoding correct as the code changes.
- Escape output for its context — HTML, attribute, JavaScript and URL escaping are different.
- Prefer frameworks that escape by default; audit every deliberate bypass (
dangerouslySetInnerHTML,v-html,|safe). - Never place untrusted values inside a
<script>block. - Tighten CSP (§6) so a future mistake is contained.
SQL injection (error-based) High if found Go-Live
We append a single syntax-breaking character to a parameter and watch for a database error that was absent from the baseline response. Read-only — we never extract or modify data.
User input is reaching a SQL statement unparameterised. Even without extracting data, a returned database error confirms the query can be broken — a direct path to full SQL injection.
- Use parameterised queries/prepared statements exclusively.
- Disable verbose database errors in production as defence in depth.
SQL injection (time-based, blind) Critical if found Go-Live · opt-in
When a parameter returns no error and no visible change, we test for blind injection: we submit input asking the database to pause briefly only if a condition holds, and compare the response time to the baseline. A reliable, condition-dependent delay means the input is executed as SQL. Delays are minimal and bounded — never destructive payloads.
The database is injectable even though nothing is reflected back — the kind that error- and content-based checks miss entirely. An attacker can extract data one inference at a time.
- Parameterise every query — the same fix as all SQL injection.
- Add query timeouts and rate limits so a timing oracle is slow and noisy to exploit.
OS command injection Critical if found Go-Live
We inject a bounded shell-arithmetic echo (e.g. $((1009×1013))) and check whether the server evaluated it — the computed marker appears only if a shell ran the input. We send nothing destructive: only harmless echo and arithmetic.
The application passes user input to an operating-system shell. This is typically full server compromise — an attacker can run arbitrary commands.
- Never pass user input to a shell. Use parameterised process APIs (argument lists, never
shell=True). - Validate against strict allow-lists and remove shell interpolation entirely.
Path traversal High if found Go-Live
We inject read-only traversal sequences (../../etc/passwd and encoded variants) and check the response for well-known system-file signatures. Nothing is written or modified.
The application turns user input into filesystem paths without containment — an attacker can read files outside the intended directory (configuration, secrets, source).
- Canonicalise paths and confirm they stay within an allow-listed base directory; reject
..and encoded forms. - Prefer opaque IDs mapped to paths server-side.
Server-side template injection (SSTI) Critical if found Go-Live
We inject a bounded arithmetic marker for the common template engines ({{1009*1013}}, ${…}, <%= … %>) and flag it only when the server evaluates the expression — the product appears while the literal does not. No code-execution payloads are sent.
User input is rendered as template source. SSTI frequently escalates to remote code execution.
- Never render user input as a template. Pass untrusted values only as sandboxed data variables.
- Patch/upgrade the template engine and enable its sandbox.
Server-side request forgery (SSRF) — reflected & blind Critical if found Go-Live
For URL-like parameters we substitute a cloud-metadata address and check whether the metadata response is reflected back (reflected SSRF). We also substitute a unique Aegis out-of-band callback URL and detect whether the server makes a request to it (blind SSRF — where nothing is reflected). The callback records only that the token was reached.
The server fetches attacker-controlled URLs. This commonly exposes cloud credentials and internal services that are unreachable from the outside.
- Do not fetch user-supplied URLs. If unavoidable, enforce a destination allow-list, resolve and pin the IP, and block link-local/loopback/private/metadata ranges.
- Disable redirects on server-side fetches.
XML external entity injection (XXE) Critical if found Go-Live · opt-in
For endpoints that accept XML, we submit a document defining an external entity pointing at a unique Aegis out-of-band callback URL, then watch whether your parser resolves it and calls us. The callback records only that the token was reached — we never read local files or exfiltrate data. Because this sends a POST body it is an opt-in heavier probe you approve explicitly.
Your XML parser resolves external entities. That can read local files (including secrets), reach internal services (a form of SSRF), and in some parsers escalate further.
- Disable external-entity and DTD processing in your XML parser — the single most important setting.
- Prefer JSON where you control the format; validate XML against a strict schema.
- Keep the parser patched.
Open redirect Medium if found Pro & above
For parameters that control a destination URL, we substitute a benign external marker and check whether the application issues a redirect to it. Read-only — we observe the redirect target, we don't follow it anywhere harmful.
An attacker can craft a link on your own domain that silently forwards users to a site they control — a strong aid to phishing, and sometimes a token-theft vector when chained with OAuth or SSO flows.
- Don't put raw URLs in redirect parameters. Use server-side keys that map to an allow-list of destinations.
- If you must accept a URL, allow only same-origin paths and reject absolute or protocol-relative targets.
9 · Authorization & access control
Authorization-differential testing Critical if found Pro & above
We sign in as two identities — typically a low-privilege user and a higher-privilege one — then replay identical requests as each and compare. If the low-privilege session receives data it shouldn't, that's broken access control. We check the final response, not just the status code, because many apps return HTTP 200 while redirecting to a "no access" page.
Broken access control is the most common serious flaw in modern applications, and automated scanners rarely find it because it requires understanding who should see what. A hit here means one customer can reach another's data, or an ordinary user can perform privileged actions.
- Enforce authorization server-side on every request. Hiding a button is not access control.
- Check ownership, not just authentication: "is this record owned by the caller?" — not merely "is the caller logged in?"
- Deny by default; require an explicit grant for each resource.
- Centralise the check so new endpoints inherit it instead of re-implementing it.
- Add a regression test per role — this class of bug returns easily.
Insecure direct object references (IDOR) High if found Pro & above
Where a resource is addressed by an identifier (/invoices/1024), we request neighbouring identifiers as a user who should not have access.
Records can be enumerated by changing a number in the URL — a trivial attack requiring no tooling.
- Verify ownership on every fetch — scope the query to the caller, e.g.
WHERE id = ? AND owner_id = ?. - Return 404, not 403, for records the caller may not see — 403 confirms the record exists.
- Unguessable identifiers (UUIDs) raise the bar but are not a substitute for the ownership check.
10 · Business-logic & state-changing tests
These change application state, so they are not part of the automated non-destructive Go-Live scan. They run self-serve — only against a non-production target you designate and explicitly approve in-app. No engineers are involved; the platform executes and gates them automatically.
Privilege escalation in workflows Critical if found Aggressive
We attempt real state-changing actions as the wrong role — approving one's own request, triggering a payment without finance rights, acting on another party's order. Each attempt is bounded and logged, with a cleanup contract.
These are the flaws that cost money rather than data: self-approved purchases, unauthorised payments, tampered orders. Scanners essentially never find them, because they require understanding your workflow — this is the closest automation gets to a human tester.
- Enforce separation of duties in the backend: the requester must not be the approver; whoever enters bank details must not release payment.
- Validate the state transition, not just the role — can this record legally move from here to there?
- Log every privileged action with the actor, and make blocked attempts auditable.
- Add a regression test per rule.
Cross-site request forgery (CSRF) High if found Aggressive
We submit state-changing requests without a valid token, and with a token belonging to a different session, to see whether they are accepted.
Another website can make your logged-in users perform actions without their knowledge — changing an email address, transferring funds, approving a request.
- Require a per-session CSRF token on every state-changing request; reject when missing or mismatched.
- Set
SameSite=Lax(orStrict) on session cookies as a second layer. - Never make GET requests state-changing.
11 · Multi-tenant isolation
Cross-tenant access & session replay Critical if found Business
With two tenants provisioned, we take an authenticated session from tenant A and replay it against tenant B — including by manipulating the host, subdomain or tenant identifier — and separately attempt to fetch tenant B's records by identifier. This needs test logins for both tenants, so it takes a few setup steps: you supply those logins and approve the run in-app. It is fully self-serve — just multi-step rather than one-click. (The underlying dual-identity engine that powers it is live self-serve for same-app IDOR — see §9.)
For a SaaS business this is the existential control. A failure means one customer can read another's data — typically a breach-notification event and, often, a company-ending one.
- Bind the session to its tenant server-side and re-validate on every request. Never infer tenancy from a header, subdomain or cookie alone — those are attacker-controlled.
- Scope every query by tenant at the data layer, so a missed check in a controller can't leak.
- Prefer per-tenant schemas or databases where practical — isolation by construction beats isolation by discipline.
- Test it continuously. This control silently degrades as features are added.
12 · Verified controls — what we prove is safe
The section other reports don't have.
Most reports list only what's broken. That leaves an auditor asking the obvious question: "what did you actually try?"
Every Aegis report includes a Verified Controls section recording the attacks we ran that failed — the exact endpoints a lower-privilege user was refused, the cross-tenant replay that was rejected, the injection probes that found nothing, and how many of each we ran. That is the evidence a reviewer needs to accept the result, and it's what turns "no findings" from an empty page into a defensible assurance.
13 · Using the report as audit evidence
What SOC 2 and ISO 27001 actually require, and where the report satisfies it.
A point of precision most vendors gloss over. There is no such thing as a "SOC 2 compliant" or "ISO 27001 certified" report — those frameworks certify organisations, not documents. What they require is that you test for vulnerabilities and act on what you find. A penetration test report is the evidence that you did. Anyone selling you a "SOC 2 certified report" is describing something that does not exist.
The controls this report speaks to
| Framework | Control | What it requires | Where the report answers it |
|---|---|---|---|
| ISO/IEC 27001:2022 | Annex A 8.8 | Management of technical vulnerabilities — identify, evaluate, act | Findings with severity, business impact and remediation; re-test after fixes |
| ISO/IEC 27001:2022 | Annex A 8.29 | Security testing in development and acceptance | Scope & methodology (Appendix A) and the dated assessment record |
| SOC 2 (TSC) | CC7.1 | Detect and monitor for new vulnerabilities | Scheduled re-scans plus the assessment history in your dashboard |
| SOC 2 (TSC) | CC4.1 | Ongoing evaluation of controls | Verified Controls — the attacks attempted that failed |
| PCI DSS v4.0 | 11.4 | External/internal penetration testing | Partially — see the caveat below |
What your auditor will ask for — and where it is
- "What was in scope?" → Appendix A, with the exact verified hosts and the tier used.
- "What methodology?" → Appendix A, plus this page in full.
- "When was it performed?" → Report header and every finding's Identified on date.
- "What did you find, and how bad?" → Master findings table with severity and state.
- "What did you do about it?" → Remediation per finding, then a re-test showing the state change to Resolved.
- "How do you know the controls work?" → Verified Controls: the attacks that were attempted and refused, with counts. This is the question most reports cannot answer.
- "Who performed it?" → Aegis, automated — stated plainly. See the caveat.
The caveat you should hear from us, not your auditor.
Aegis is automated testing. Many auditors accept automated penetration-test evidence for SOC 2 and ISO 27001 — but your auditor decides, and some engagements specifically require a named, qualified human tester. That is common for PCI DSS 11.4 and in government or defence procurement. If yours requires a human, no automated product — ours or anyone's — satisfies it, and you should hire a consultancy. Ask your auditor before you buy; we would rather lose the sale than have you fail an audit holding our report.
14 · What we don't test — and why that matters
Stated plainly, because a vendor who claims to test everything is telling you something untrue.
| Not tested | Why |
|---|---|
| Denial-of-service, load, stress | Deliberately excluded — the risk of harming your service outweighs the finding. |
| Provider infrastructure (Cloudflare, AWS, DigitalOcean…) | Not yours to authorise. Blocked in code. |
| Social engineering & phishing | Targets people, not systems. Needs a human-led engagement. |
| Physical security | Out of scope for an application test. |
| Source-code review (SAST), dependencies (SCA), containers | A different discipline. We test the running application from the outside, as an attacker meets it. |
| Novel zero-day discovery | Requires human creativity. Automation tests known and structural classes exceptionally well; it does not invent new attacks. |
The honest bottom line. No automated test proves the absence of vulnerabilities. A clean Aegis report means the checks we ran — documented above, in full — found nothing. That is genuinely valuable evidence, and it is not the same as "your system is secure." Any vendor implying otherwise is selling you certainty that does not exist.