TL;DR: Three low findings on a maintained platform sound like a pass. I explain why a low-severity result is only a statement about the vectors I chose, and where the next assessment should start.
The scenario
I ran this as a black-box review: no credentials, only the publicly visible surface. Here is what I saw before I touched anything.
A regional cooperation and counselling platform on a maintained enterprise content system behind a reverse proxy, with a current PHP runtime. Assessment covered version posture, header policy, information disclosure and the exposed administrative surface.
I removed all identifying information. The target is described only by sector and technology class so the pattern can be reused.
The pattern
The pattern I recognised — and that I keep finding in similar estates:
A low-severity result is a statement about the vectors you chose, not about the system. Three low findings on a maintained platform usually means the platform is current, the plugin set is small and the interesting surface is behind something. It does not mean there is nothing to fix; it means the fixes are hygiene items, and hygiene items decay quietly.
The reason this engagement is worth writing up is the shape of the estate. A cooperation platform handles appointments, counselling requests and internal notices. The content system is only the delivery layer, but the data model behind it distinguishes anonymous readers from authenticated participants, and the distinction lives in the routing and session layer rather than in the content. That is where the next audit should start, and this one deliberately did not pretend to have covered it.
The concrete lesson is about sequencing. Header policy, version posture and disclosure fixes are cheap, immediate and permanent once scheduled. Session and authorisation design is expensive and requires knowing what the platform actually does for whom. Doing them in the wrong order wastes the easy wins; doing them in the right order means the version fix that raises a floor never has to be repeated.
Findings
| Severity | Finding | Evidence |
|---|---|---|
| NIEDRIG | Security headers absent on the public surface | No frame, referrer or content-type protection |
| NIEDRIG | Content system version in asset paths | Exact release identifiable |
| NIEDRIG | No published security contact file | No channel for coordinated disclosure |
| INFO | Platform and runtime current | No known vulnerability in the core platform |
| INFO | Administrative paths restricted | No writable endpoint reachable anonymously |
| INFO | No reflected input in public forms | No exploitable injection point found |
The attack path
Reproduction in my lab
Every command below targets a lab container I control. Nothing here is aimed at a live system.
Establish the baseline on your own platform
$ for h in example.org; do
printf '%s\n' "$h"
curl -sI "https://$h/" | grep -iE 'strict-transport|content-security-policy|x-frame|x-content-type|referrer-policy|permissions-policy' || echo ' no security headers'
curl -s "https://$h/" | grep -oiE 'generator[^>]*content="[^"]+"' | head -3
curl -so /dev/null -w ' security.txt -> %{http_code}\n' "https://$h/.well-known/security.txt"
done
Detection in your own estate
Test whether the anonymous and authenticated surfaces differ
# the same path, before and after a session, should differ in behaviour not in existence
$ curl -so /dev/null -w 'anonymous %{http_code}\n' https://example.org/termine
$ curl -so /dev/null -w 'with-cookie %{http_code}\n' \
-H 'Cookie: session=<your-own-test-session>' https://example.org/termine
# check what a full session can reach that anonymous cannot
$ curl -s https://example.org/ | grep -oE 'href="/[a-z0-9/-]*"' | sort -u | head -20
Remediation
Ship the header baseline in the platform configuration, once
# baseline for every response on the estate
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; frame-ancestors 'self'; base-uri 'self'" always;
server_tokens off;
Publish a security contact file
# .well-known/security.txt
Contact: mailto:security@example.org
Expires: 2027-12-31T23:59:59.000Z
Preferred-Languages: en, de
Canonical: https://example.org/.well-known/security.txt
Policy: https://example.org/security-policy
Takeaways
- Low severity means your vector list was short, not that the system is safe.
- Content systems are the delivery layer; authorisation lives one level down.
- Fix header and version hygiene first, because they raise the floor permanently.
- Write down what the assessment did not cover, so the next one starts there.