Skip to content

Penetration Test Runbook

How Gevell commissions, runs, and closes out a third-party penetration test.

Status: no penetration test has been performed. Tracked as issue #3096. This runbook exists so the test can be started on short notice β€” institutional customers ask for one during security review, and it is the cheapest piece of evidence that satisfies the question. The customer packet states plainly that a test is planned and can be prioritized at contract time; this is how we keep that promise.

Budget roughly 4–6 weeks end to end: 1–2 weeks to select a vendor and agree scope, 1–2 weeks of testing, 1 week for the report, then remediation and retest.


1. Decide the scope

Scope narrowly and deliberately. A broad scope costs more, takes longer, and produces findings on things we do not control.

In scope β€” the customer-facing surface:

TargetWhy
pdf.gevell.com Β· audit.gevell.comPrimary applications; authenticated and unauthenticated
acr.gevell.com Β· orgchart.gevell.comDistinct auth and tenancy surfaces
api.gevell.com Β· api-pdf.gevell.comThe API behind all of it; test both compositions β€” they are built from one source tree but deployed differently
Authentication and session handlingEmail/OTP, SAML SSO, LTI 1.3 launch, API keys
Tenant isolationThe highest-value target: cross-tenant read/write, IDOR on job and file identifiers, 404-not-403 behavior
File upload pathPresigned URL abuse, type and size bypass, malware-gate bypass, path traversal in object keys
SSRF surfacesPOST /api/v2/fetch-url and the parse service fetch both take customer-supplied URLs; the allow-list is the control under test
Published artifactsShare tokens, published org charts, expiry and revocation

Explicitly out of scope:

  • Cloud provider infrastructure (AWS, Cloudflare, Supabase) β€” inherited controls under their own attestations; testing them is prohibited by their terms except under their published policies.
  • Denial-of-service and volumetric load testing.
  • Physical and social engineering, unless the customer specifically requires it.
  • Third-party AI endpoints (Bedrock, Mathpix).

Decide before soliciting quotes: grey-box (credentialed, our preference β€” tenant isolation cannot be meaningfully tested without accounts) versus black-box; and whether a retest of fixed findings is included in the price.


2. Select a vendor

Ask each candidate for: a redacted sample report, tester certifications (OSCP/OSWE/CREST or equivalent), whether findings are manually verified or scanner output, whether a free retest is included, and turnaround time.

Prefer a firm that issues a letter of attestation alongside the report β€” a one-page summary we can hand to a customer without disclosing findings. That letter, not the report, is what usually closes the procurement question.

Confirm the firm will sign an NDA and will not retain our data after the engagement.


3. Before testing starts

  • Signed scope document, NDA, and rules of engagement, naming the exact hosts, the test window, and the tester source IP addresses.
  • Notify AWS and Cloudflare per their penetration-testing policies. AWS permits testing of customer-owned resources for approved service types without prior approval; anything outside that list needs a request. Cloudflare requires notice for testing through their edge.
  • Stand up an isolated test tenant with seeded synthetic data. Never point a test at production customer documents.
  • Create at least three test accounts across two tenants, so cross-tenant isolation can actually be exercised, plus one API key.
  • Allow-list tester IPs in the WAF, or agree explicitly that WAF blocking is part of the test.
  • Silence or tag alerting for the window so tester traffic does not page us β€” but keep it recorded, because whether we detected the test is itself a finding worth having.
  • Snapshot the environment: commit SHA, build number, deployed versions of each composition. The report must name what was tested.
  • Nominate a single point of contact (CTO) reachable during the window.

4. During the test

  • Keep a shared channel with the testers for real-time questions.
  • Critical findings are reported immediately, not held for the report. Agree this in the rules of engagement.
  • Do not fix anything mid-test without telling the testers β€” a silent fix invalidates their retest baseline.
  • Log any production impact. If the test degrades service, that is an incident and follows the incident process.

5. Triage the report

For every finding:

  1. Reproduce it ourselves before accepting it. Scanner-derived findings are often environmental or false.
  2. File a GitHub issue labeled security, one per finding, with the severity the report assigned and a link to the relevant section.
  3. Set the remediation target by severity: critical β€” 7 days, high β€” 30 days, medium β€” 90 days, low β€” next planned work.
  4. Where we accept a risk rather than fix it, write the justification down. A documented accepted risk is a defensible answer; an unexplained open finding is not.
  5. Add a regression test for anything exploitable. A finding that can recur silently has not been fixed.

6. Close out

  • Retest critical and high findings and get written confirmation.
  • Obtain the letter of attestation.
  • Update the customer packet: replace the β€œnot yet” answer in Direct Answers and Β§9.9 of each technical specification with the test date, scope, and firm.
  • Update the security white paper’s certifications section and remove the corresponding gap from its internal appendix.
  • Record the next test date. Annual is the expectation reviewers hold, plus a retest after any architectural change to auth, tenancy, or the upload path.
  • Store the full report where it can be shared under NDA β€” not in the repo.

7. What to hand a customer

Give them the letter of attestation and a summary: date, scope, firm, methodology, count of findings by severity, and confirmation that critical and high findings were remediated and retested.

Do not send the full report. It is a map of the application for anyone who obtains it. If a customer insists, send it under NDA, directly to a named security contact, never as a public link.


Security White Paper Β· HECVAT answer set Β· AI Data Protection