graphai jobs
Sign in

Jobs › Blog › Security review

10 Sep 2026 · Graphai Jobs

Defensive review and fixes on jobs.graphai.eu

The jobs studio was checked with the in-repo Playwright security suite, then the findings that could be fixed in this repo were landed the same day. This is a defensive QA pass, not an offensive penetration test. No login brute force, no fuzzing, no scanner tools, and no exploit payloads.

Related: authorized review of graphai.eu · Linear test plan in the private jobs repo (e2e/TESTPLAN.md).

Scope

Tool: Playwright

Playwright is a browser and HTTP testing library. For this pass we used @playwright/test 1.62.1 from the jobs repo, with playwright.config.mjs pointed at production (JOBS_BASE_URL defaults to https://jobs.graphai.eu).

The security file is e2e/security.spec.js. It uses Playwright’s request fixture (HTTP only, no browser) so checks stay at status codes, redirects, and headers. The suite is labelled “defensive web checks” on purpose: it asserts what a signed-out visitor must not receive. It does not send injection strings or scan for CVEs.

The same repo also has related QA tools that were not required for this pass:

Source of truth for the studio is the private GitHub repo that Vercel builds from. Production client errors that users consent to send go to Sentry (EU). Sentry Seer opens GitHub pull requests from those incidents; those stay in the private repo, not on this page.

Command run:

./node_modules/.bin/playwright test e2e/security.spec.js --reporter=list

What we exercised

CheckWhat Playwright asserted
LandingHTTPS 200 with an HTML/text content type
HSTSStrict-Transport-Security includes max-age=
CORSLanding Access-Control-Allow-Origin is not *
Gallery HTMLUnauthenticated GET redirects (3xx) to sign-up, not the studio
Gated HTML/gallery and /gallery.html are not served as 200 app HTML when signed out
Gated APIs/api/recommended, /docs, /inbox, /probe, /policies, /applications, /progress-report, /report return 401–499 when signed out
Open redirect/sign-up.html?next=https://evil.example/ does not echo that host in the HTML
Apply ingestAnonymous POST /api/apply-spot is not treated as a successful worker ingest
Feature requestEmpty POST to /api/feature-request is rejected (not a silent 200)

Result of this run: 17 passed, 0 failed (4 workers). The CORS check was added after reading GitHub issue 3 / Linear GRA-157.

What is already solid on the public host

CheckObserved 10 Sep 2026
TLSTLS 1.3, Let’s Encrypt, CN jobs.graphai.eu, valid through 22 Nov 2026
HSTSmax-age=63072000; includeSubDomains
X-Content-Type-Optionsnosniff
X-Frame-OptionsDENY
Referrer-Policystrict-origin-when-cross-origin
Permissions-Policycamera and microphone empty; geolocation and passkeys limited to self
CSPframe-ancestors 'self', plus base-uri 'self', object-src 'none', and upgrade-insecure-requests in the follow-up patch
CORPsame-origin
CORSAccess-Control-Allow-Origin: https://jobs.graphai.eu (not *). Linear GRA-157 is Done.
Gallery gateSigned-out /gallery.html lands on sign-up
robots.txtAllows /blog; disallows /api/ and /gallery

What we changed after the first pass

Same-day patches on the jobs repo (private GitHub jobs-graphai-eu):

Local unit tests after those patches: 116 passed. The Playwright file grew to 20 checks (CORS, security.txt, next= helper, public comments GET). Production only matches the new checks after this deploy.

What we did not do

We did not authenticate as a beta user, did not send exploit payloads, and did not scan with Nuclei or sqlmap. A 401 on /api/inbox is proof that this path is gated for anonymous GET — not a proof that every authenticated handler is perfect. Payment webhooks, worker ingest with a valid secret, and Clerk session forgery were out of this pass.

Follow-up

  1. Keep e2e/security.spec.js in the hourly GCP Playwright loop so a regression reopens a GRA bug.
  2. The company landing review remains at graphai.eu web security review.

Graphai OÜ. Contact hello@graphai.eu.