Application security guide

Security requirements written so an engineer can act on them

"The system must comply with the OWASP Top Ten" is not a requirement, and writing it does more harm than leaving the section blank. The Top Ten is an awareness document describing categories of risk; it contains nothing an engineer can implement and nothing a tester can fail. A requirement that cannot be failed will not be built, will pass review, and will be discovered as missing during a penetration test months later. The fix is a form, and it takes one sentence.

Why does referencing a risk list fail as a requirement?

Because it names a category rather than a behaviour. "Prevent broken access control" tells the engineer nothing about which objects need ownership checks, what the response should be when the check fails, whether the failure should be logged, or how anyone would demonstrate that it works. Two competent engineers will implement it differently and both will believe they complied. Nobody is wrong, because nothing was specified.

If you want a standards-based source, the useful one is the OWASP Application Security Verification Standard, which is deliberately structured as individually verifiable statements arranged in levels, so a project can adopt a level and a tester can work through it. That is a requirements document. The Top Ten is a communications tool for explaining why the requirements exist, and the two get confused constantly in contracts and tender responses.

Run this test on your own backlog. Take the last three security requirements written for your team and ask, for each, what a tester would do to produce a failing result. If the answer requires interpretation, the requirement is a sentiment. This is the fastest way to see how much of your security specification is decorative.

What makes a security requirement testable?

A trigger, a required behaviour, and a verification method. "When a request references a record the authenticated caller does not own, the service must return not-found and emit an authorisation-denied event containing the actor, the object and the timestamp; verified by an automated test in the service suite." That sentence is implementable by someone who has never spoken to you, and it fails visibly when unimplemented.

Two details in that example carry most of the weight. Specifying the response, not-found rather than forbidden, resolves a design question the engineer would otherwise decide by coin flip, and it prevents the response itself confirming that the record exists. Specifying the log fields means the detection capability arrives with the feature rather than being retrofitted during an incident when the events are needed and absent.

Avoid the word "appropriate" and every relative of it: adequate, sufficient, industry-standard, best practice, reasonable. Each one moves the decision from the person writing the requirement to the person least equipped to make it, and each one is unfailable at review. If you genuinely do not know the value, write the requirement with a placeholder and a name against it rather than a vague adjective.

Where should security requirements come from?

Four sources, and knowing which one a requirement came from tells you how negotiable it is. The threat model for this feature produces the specific ones, and they are the most valuable because they are grounded in a discussed attack. Regulation and contract produce the non-negotiable ones. The platform standard produces the ones that should already be true. Incidents and penetration tests produce the ones with the strongest evidence behind them.

Attach the source to the requirement in the ticket. An engineer facing a delivery deadline makes better trade-off decisions when they can see that one requirement came from a data processing agreement with a named customer and another came from a general preference. Requirements with no provenance are the first to be dropped, correctly, because nobody can weigh them.

Where the requirement derives from a legal obligation, write the obligation and the control separately, because they change on different timescales and because obligations differ by jurisdiction. "Personal data in this table must be encrypted at rest" is a control. The reason it exists, and whether it is actually mandatory for you, is a question for counsel, and the requirement should say which one it is rather than blurring them.

What does the rewrite look like?

Mechanical, once you have the pattern. The unusable versions below are all real phrasings in common use, and in each case the rewrite is not longer, only more specific.

AreaUnusable versionUsable versionVerified by
Access controlEnforce proper authorisationRequests for a record the caller does not own return not-found and log a denial eventAutomated test per resource type
Rate limitingProtect endpoints against abuseThe login endpoint permits ten attempts per account per hour, then requires a second factorLoad test asserting the rejection
LoggingLog security-relevant eventsAuthentication, authorisation denial and permission change events record actor, object, source address and timeQuery the log store for a seeded event
TransportUse strong encryptionOnly TLS 1.2 and above are accepted, with a named cipher list, and plain requests redirectAutomated configuration scan in the pipeline
Container runtimeHarden containersContainers run as a non-root user with a read-only root filesystem and no added capabilitiesAdmission policy that rejects non-compliant workloads
DependenciesKeep dependencies up to dateNo deployed artefact carries a known-exploited advisory with an available fix older than seven daysPipeline check against the artefact inventory

Which requirements should be defaults instead?

Any requirement you have written more than twice. Cookie attributes, transport configuration, container runtime settings, log format, secret retrieval, dependency policy: these should be properties of the platform or the service template, enforced by a pipeline check or an admission policy, not sentences in a story. A requirement that recurs is a signal about your infrastructure, and repeating it per feature guarantees inconsistent adoption.

The distinction to hold onto is that per-feature requirements should be about this feature's specific trust decisions, which no template can anticipate. Which objects need ownership checks, what the state machine forbids, what the rate limit should be given real usage, which fields are sensitive enough to exclude from a response. Those are irreducibly local, and if the security section of your stories is instead full of platform items, the platform work has not been done.

Promoting a requirement to a default has a cost worth naming: it must be enforced automatically or it decays into a document. Enforcement in the deployment path, where a non-compliant workload is rejected rather than reported, is the version that lasts, because it does not depend on anyone reading anything.

How do you write abuse cases into a story?

As negative acceptance criteria, in the same format as the positive ones, sitting in the same list. If the story says a customer can download their own invoice, the abuse criteria say that a customer cannot download another customer's invoice, that an unauthenticated request cannot, that a customer whose access has been revoked cannot, and that a bulk download loop is throttled. Four lines, all testable, all derived from the same sentence.

This works because it puts the negative case in front of the person who writes the code, at the moment they are deciding the structure, rather than in front of a reviewer afterwards. It also produces tests that persist. An assertion that another tenant's invoice returns not-found runs on every commit forever, which converts a one-time review finding into a permanent property.

Keep the list short. Three or four abuse criteria on the stories that touch money, personal data or permissions, and none at all on the ones that do not, is a workable and sustainable pattern. Demanding them everywhere produces copy-paste, and copy-pasted acceptance criteria are indistinguishable from no criteria within about a month.

Common questions

Is the OWASP Top Ten a set of requirements?
No. It is an awareness document describing categories of risk, useful for explaining why controls matter and unusable as a specification, because it contains nothing an engineer can implement and nothing a tester can fail. Writing it into a contract or a story creates the appearance of a requirement with none of the substance. The standards-based alternative is the OWASP Application Security Verification Standard, which is structured as individually verifiable statements grouped into levels a project can adopt.
What makes a security requirement testable?
A trigger, a required behaviour and a verification method in one sentence. For example: when a request references a record the authenticated caller does not own, the service returns not-found and emits an authorisation-denied event with actor, object and timestamp, verified by an automated test. Specifying the response and the log fields removes decisions the engineer would otherwise make arbitrarily, and makes the requirement fail visibly when unimplemented.
Why should you avoid words like appropriate in security requirements?
Because they transfer the decision to whoever is least equipped to make it, and they cannot be failed at review. Adequate, sufficient, industry-standard, reasonable and best practice all describe a feeling rather than a behaviour, so two engineers will implement different things and both will believe they complied. If the correct value is genuinely unknown, use a placeholder with an owner's name rather than a vague adjective.
What are abuse cases and where do they belong?
Negative acceptance criteria written in the same format and the same list as the positive ones. If a story says a customer can download their own invoice, the abuse criteria state that another customer cannot, an unauthenticated caller cannot, a revoked account cannot, and bulk downloading is throttled. They belong in the story so the person writing the code sees them while deciding the structure, not afterwards in review.
Which security requirements should become platform defaults?
Any requirement written more than twice: cookie attributes, transport configuration, container runtime settings, log formats, secret retrieval and dependency policy. Recurrence is a signal about your infrastructure rather than about the feature. Promote them to a service template enforced by a pipeline check or an admission policy that rejects non-compliant workloads, because a default that is documented rather than enforced decays quickly.
How many security requirements should a user story have?
Three or four abuse criteria on stories that touch money, personal data or permissions, and none at all on stories that do not. Requiring them universally produces copy-paste, and copy-pasted acceptance criteria stop being read within about a month. The per-feature requirements worth writing are the ones about this feature's specific trust decisions, such as which objects need an ownership check and what the state machine forbids, because no platform template can anticipate those.

More on Application security

Let’s create something out of this world together.

Have a project in mind? Contact us for expert design and development solutions. Let’s discuss how we can help grow your business.

Azaadi Offer

Claim a free security assessment

Until 31 August we're covering the cost of a full vulnerability assessment and penetration test. Mention it in your message and we'll scope it with you.

  • Web application testing, authenticated and unauthenticated
  • Mobile application testing across iOS and Android
  • External network and infrastructure assessment
  • Manual exploitation by engineers, not scanner output

Testing and the report are free. Fixing what we find is quoted separately, with no obligation to accept.

Read the full offer

Tell us what you are trying to build and we will tell you plainly whether we are the right people for it. Book a call with an expert to work through the detail, or ask for a fixed quote if the scope is already clear. No obligation either way.

Four fields is all we need to get started.

Fastnexa Logo

© 2026 fastnexa. All rights reserved.