Security
What is actually implemented on this site, and what is not. Written for readers who would rather have the short honest list than the long impressive one.
RETEC is a small studio. This page describes the security of our website and the applications we build — honestly, and without the vocabulary of a compliance programme we do not run.
The rule we have applied while writing it: if a control exists in the code or the infrastructure, it is described. If it does not, it is not mentioned. Where a practice depends on configuration, it says so.
- Last updated
Security at RETEC
There is no dedicated security team, because there is no security team to have. Security here is the responsibility of the person who builds and runs the systems, alongside the rest of the work.
That shape has an obvious consequence worth stating plainly: there is no 24/7 operations centre watching anything. Systems are monitored in the ordinary way — by the infrastructure they run on and by application logging — not by a team on a rota.
RETEC holds no formal security certification. We do not hold SOC 2, ISO 27001 or PCI DSS, we have not commissioned a penetration test, and we do not describe anything here as certified, audited or compliant with a framework. If you need a vendor with those, this is not that.
What we do have is a small set of controls we actually keep, and this page describes them accurately.
Application Security
Transport
The site is served over HTTPS, and form submissions are encrypted in transit. The application is deployed behind a proxy and is configured to trust exactly one proxy hop for the forwarded protocol and client address, so a client cannot spoof either by sending the relevant headers directly.
Authentication
Administrative access is restricted to a single account. The password is stored as a bcrypt hash; the plaintext password is never written to the database, and cannot be recovered from it. Login attempts are rate limited per source address, with a tighter allowance than general site traffic.
Session handling
Authentication state is held in a signed, server-validated session cookie. It is not a bearer token containing readable claims, and the signing key is a secret held in environment configuration.
Authorization
Every administrative route is guarded by an authentication check performed on the server for each individual request. Hiding a link in the interface is not part of that, and removing the guard from one route is not a supported configuration.
Request forgery
Form submissions that carry visitor input are protected with cross-site request forgery tokens. A small number of endpoints are deliberately exempt — the newsletter signup, the analytics receivers and the admin image upload — because they are either unauthenticated by design or unreachable without an authenticated session.
Input Validation
All public input is validated on the server, never only in the browser. Validation is allowlist-based wherever a value comes from a fixed set of choices, so an unexpected value is rejected rather than coerced.
- Fields are length-bounded, so an oversized submission cannot be stored or forwarded.
- Email addresses are format-checked, and newsletter addresses are additionally verified against a deliverability service before they are stored.
- URL fields accept only http and https, reject non-web schemes such as javascript: and data:, reject embedded credentials, and reject hosts containing a wildcard, port or path.
- Uploads are restricted to an allowlist of image and video extensions, renamed to a generated filename, and capped at 16 MB per request.
- Request bodies are size-capped at the web server and application layer.
Content published to the Journal is parsed and re-emitted from a fixed allowlist of tags and attributes, and broken or unbalanced markup is discarded. Published content is not a free path for script injection.
Infrastructure and Hosting
The application runs on a managed web host behind a CDN, with a managed PostgreSQL database. The CDN terminates client connections and the host runs the application under a WSGI server.
- A web application firewall sits in front of the application and filters the common classes of malicious request before they reach the code.
- TLS is used for all connections, including to the database. The application refuses to connect to a remote database without TLS enabled.
- Responses are served with caching disabled so that personalised or administrative pages are never stored in a shared cache.
- Static assets are public and cache-busted by a version query string.
Hosting headers such as HSTS and the CDN's own protections are configured at the provider rather than in the application source, so they can change without a code change. This page describes them as configured, not as guaranteed.
Data Protection
- Passwords are bcrypt-hashed and never stored or logged in plaintext.
- Database credentials, third-party API keys and the session signing key are held in environment variables on the server. None of them are committed to source control; the files that hold them are excluded from the repository.
- Uploaded filenames are generated rather than taken from the client.
- Administrative and diagnostic output goes to server logs rather than into responses.
- SMTP and third-party API traffic is made over TLS.
Where practical, secrets have been removed from source control entirely. Where a credential was ever committed, it should be treated as compromised and rotated rather than relied upon — rotation is a matter of record-keeping, not of code.
Access Control
The administrative area is a single-account model. That is the whole design, and it has an obvious property: there is exactly one identity to grant, revoke and audit.
- Access is granted by possession of the credentials, and the account is not shared. If someone else needs access, they need their own.
- A password change requires proving the current password first, and the confirmation step expires after a short window.
- There is no separate read-only, editor or viewer role, and no per-object permission model.
The principle applied throughout is least privilege: the application holds the database credentials it needs and no more, and a compromise of the web tier does not by itself grant access to anything beyond it.
Two independent safeguards guard destructive database operations. The application refuses to boot against a remote database unless explicitly allowed, and refuses to drop tables unless two separate confirming environment variables are both set. A single leaked environment variable is therefore not sufficient to destroy the database.
Backups
The database is backed up by an operator-run script that produces a timestamped, compressed SQL dump and stores it outside the database provider. Older dumps are pruned on a rolling basis.
This exists because a managed database plan without a point-in-time restore is not a backup strategy. It has already been learned the expensive way.
- The dump script is read-only: it never writes to the database it is backing up.
- Backups are stored outside the database provider, so a provider-side failure does not take them with it.
- There are tools to list, verify and restore a dump.
[TODO: ...]: confirm how often the backup job actually runs. The script exists and is tested; a backup that nobody schedules is not a backup, and this page should not imply otherwise.
Logging and Monitoring
There is no dedicated monitoring service and no alerting pipeline of our own. What exists is standard:
- Application logging records failures — email delivery errors, third-party API errors, upload failures, scheduler errors — with enough context to diagnose them.
- The hosting platform logs requests and serves the site.
- First-party analytics record page views, section interest and coarse location, which is how unusual traffic would first become visible.
None of this constitutes 24/7 monitoring, and nobody is paged. If you are assessing RETEC for a role that requires a documented incident response capability with guaranteed response times, this is not a match.
Third-Party Services
RETEC depends on other companies. Each one is a place where our security is somebody else's security, so they are named here rather than left implicit.
- Managed web host and CDN
- Runs and fronts the application. Secures client connections.
- Managed PostgreSQL provider
- Stores the application data, including the personal information described in the Privacy Policy.
- Transactional email and SMS provider
- Holds a contact list and delivers messages. It has seen every inquiry email address and message body.
- Email deliverability provider
- Receives addresses submitted for verification.
- IP geolocation provider
- Receives IP addresses and returns a country and city. Note that this lookup is made over plain HTTP; the response is not confidential information, but the request is visible in transit.
- Public CDNs
- Serve fonts, icons and animation libraries. They see the requests that reach them, which include IP address and browser string.
- Cloudinary (optional)
- Stores uploaded media when configured. With no configuration the application stores uploads locally instead.
- AI language-model API (optional)
- Used to draft summaries of public news articles for the Journal. It operates on retrieved public content and does not receive visitor personal data.
Each of these has its own security posture and its own terms. We rely on their controls; we do not audit them, and we have not verified their compliance status on your behalf.
Secure Development
- Dependencies are pinned to specific versions, so a build is reproducible and an upgrade is a deliberate act rather than an accident.
- Framework, driver and library versions are kept current, and security-relevant updates are applied deliberately.
- Secrets are configured through the environment, which keeps them out of the source tree and out of the templates.
- Templates escape output by default; raw HTML is only used where content has been through the sanitiser.
- Destructive database operations are guarded by a module that requires two independent confirmations, so a development convenience cannot reach production data.
- Form handling is rate limited, and forms carry a hidden field that rejects automated submissions before any mail is sent.
- New routes that read or write protected data are expected to carry the authentication decorator; this is checked in review.
RETEC is a small team, so the honest statement about process is this: these practices are followed deliberately, and they are not audited by anyone outside the studio.
Incident Response
There is no formal, documented incident response plan with defined severity levels and response times. What happens in practice is that the person who built the system is the person who responds to it.
The order of operations, when something is wrong:
- Establish what actually happened and what is affected. Log records and application errors are the starting point.
- Contain it — revoke credentials, remove access, disable the affected route — before investigating further.
- Rotate anything that may have been exposed: application keys, database credentials, third-party API keys, the session key. Rotation is assumed, never assumed to be unnecessary.
- Assess who was affected and what of theirs was involved.
- Tell those affected, plainly and without overstating confidence, and say what was done.
If you are assessing us as a vendor, this section is the one to weigh most carefully. It is small, and it is written to be readable by a person rather than to satisfy a checklist.
Responsible Disclosure
If you find a vulnerability in this website or in something we have built, we would rather hear about it quietly than read about it publicly.
Please report it privately, and please give us a reasonable opportunity to assess and fix it before disclosing details.
What to include
- What the issue is, and how to reproduce it.
- Which page, endpoint or project it affects.
- What an attacker could do with it.
- Any proof-of-concept you are willing to share privately.
- How to reach you, and how long you are willing to wait.
What to expect
- An acknowledgement that the report arrived.
- An honest assessment — including being told that something is not in fact a vulnerability, or that we are not going to fix it.
- No public attribution unless you ask for it.
There is no bug bounty programme and no financial reward attached to a report. We are a small studio and cannot offer one honestly. The incentive here is the same as it would be anywhere else: a working system.
Please do not access data that is not yours, do not degrade the service for others, and do not use automated scanning. We will not pursue action against good-faith research that stays inside these lines, but we will not tolerate destructive testing.
Contact
Security reports and privacy enquiries go to the same mailbox as all other correspondence. That address is configured, so a report reaches a person rather than an unattended form.
Security disclosures [email protected][TODO: ...]: set SECURITY_CONTACT_EMAIL if reports should be routed to a dedicated mailbox. Until it is set, they arrive in the studio inbox alongside project enquiries, which is honest but not ideal.
If a report turns out to be urgent — active exploitation, exposed credentials — say so in the subject line so it is not buried among enquiries.