Quality and Security

Application Security Basics

The core properties that keep a web application safe when input, accounts or dependencies cannot be fully trusted, from threat modelling and object-level…

Chapter 54Quality and Security

Other parts of this course deal with the quality of requirements, with checks, and with secrets and credentials. This unit focuses on how the product itself behaves when its input data, an account or a dependency cannot be considered fully trustworthy. Application security is not a single switch and not a scanner certificate. It is a set of system properties that help keep data safe, perform only permitted actions, limit damage and notice failures.

The material here applies to web applications and server-side components in general terms. Specific settings depend on the framework, the data store, the sign-in method, the client platform and the deployment environment. The Open Worldwide Application Security Project (OWASP) publishes the Application Security Verification Standard (ASVS), an open standard of technical security requirements for web applications. At the date of checking, the stable version of ASVS was 5.0.0. It is a map of control requirements, not a promise that any product with the boxes ticked is protected against every threat. (OWASP ASVS 5.0.0)

Start with the threat and the trust boundaries

A threat is a situation in which someone or something can cause an outcome the product does not want. A threat model is a structured description of what needs protecting, who interacts with the system, where the trust boundaries lie, what can go wrong and which measures reduce the risk. OWASP describes threat modelling as a repeatable process and recommends starting from the architecture, data flows and trust boundaries; there is no universal method that is equally right for every team. (OWASP Threat Modeling Cheat Sheet)

For a first pass, answering six questions is enough:

Question Example for a supplier portal
Which asset must be protected? Contracts, invoices, contact details and the right to approve a payment.
Who interacts with the system? A supplier representative, a procurement employee, an administrator and an external file importer.
Where are the entry points? Web pages, the application programming interface, document uploads, an image URL.
Where does the trust boundary run? Between the browser and the server; between a supplier's request and other suppliers' data; between the application and a fetched address.
What can go wrong? A user reads someone else's invoice, a document executes as active content, or the importer reaches an internal system.
Which control, and what residual risk? A server-side access check reduces the risk of reading other people's data, but an invoice linked to the wrong supplier in the first place still needs checking.

Confidentiality is not the only thing to protect: changing someone else's invoice threatens integrity, expensive mass requests threaten availability, and keeping more contact data than needed threatens privacy. For each threat, name the possible impact and check the assumptions the control relies on. If the server imports an address supplied by the user, find out where it can connect and what data it can reach.

A control reduces risk but does not remove every assumption. For a scenario, name which data could be exposed, which action an outsider could perform and which product function could be stopped. For an address imported from the browser, separately establish who supplies the address, which component makes the request, and which resources that component can access.

A product owner can ask the team to show evidence: where the server checks the right to an object; which test confirms refusal for another organisation; how a library vulnerability is reported and who decides on the update; how long a file is kept after deletion. Answers such as "there's a login", "the scanner is green" or "the identifiers are random" do not, on their own, prove that the relevant risk is under control.

Signing in answers a different question from permission

Authentication establishes who is making the request; authorisation checks whether that person may perform a specific action on a specific resource. A successful sign-in does not grant access to every invoice: OWASP recommends denying by default and checking permission on every request. (OWASP Authorization Cheat Sheet)

When signing in, the user authenticates for a session, and the browser may automatically attach that session's credentials to later requests. In other authentication schemes the client sends an access token: a secret that links the request to an earlier authentication; its lifetime and revocation method depend on the protocol and the application.

A cookie is a small value the browser sends along with a request. In a typical web application the session identifier is stored in a cookie. The Secure flag restricts sending it to HTTPS connections, HttpOnly prevents browser scripts from reading the value, and SameSite restricts sending it in cross-site requests. The right combination of flags depends on the sign-in method and product compatibility.

For a bearer token, it is just as important to know where it is stored, to whom it is passed and how it is revoked: its lifetime and behaviour depend on the protocol and the application.

The server must end a session after sign-out, after a defined period of inactivity or after an absolute lifetime; the exact periods depend on the sensitivity of the data and the workflow. Deleting the cookie only in the browser is not enough if the server still accepts the old session. (OWASP Session Management Cheat Sheet)

The practical conclusion for a product decision: use a proven implementation of sign-in and sessions from a current framework or a specialised provider. Do not build your own cryptography, session protocol or account-recovery mechanism without a strong reason and the expertise to do it. Discuss with specialists the lifetimes, revoking all active sessions after account recovery, multi-factor requirements for especially sensitive actions, and the consequences of a lost device.

Transport Layer Security (TLS) protects data in transit between client and server, including through HTTPS (Hypertext Transfer Protocol Secure). It helps preserve the confidentiality and integrity of the stream and confirms to the client that it has connected to the expected server. Once the transfer is complete, however, the data sits in a system governed by rules for access, caching, logging and storage. TLS does not prevent excessive internal access and does not replace authorisation. (OWASP Transport Layer Security Cheat Sheet)

Check the right to every object on the server

The client interface can hide a button, and a record identifier can be long and random. Both are useful for user experience or for making guessing harder, but neither replaces a server-side check. A user can modify a request, repeat it or use another available route. The server must reconcile the current person, the action, the resource, the owning organisation and the policy of roles or relationships. This class of defect is often called an insecure direct object reference: a resource is reachable by its identifier, but its owner is never checked.

Worked example 1: someone else's invoice in the portal

Situation. A supplier portal shows invoices. The agreed requirement says an employee of a company sees only their own company's invoices. After sign-in, the browser sends an invoice number to the server, which looks the record up by number alone.

Minimal counterexample. The server confirms that the session belongs to a user, finds the invoice by number and returns it. This proves authentication but skips data-level authorisation: the lookup is not restricted to the organisation that the active session belongs to.

Solution. The server takes the organisation identifier from the trusted session context and includes it in the query check. Illustrative query pseudocode:

SELECT invoice_number, total, due_date
FROM invoices
WHERE invoice_id = :invoice_id
  AND supplier_id = :current_supplier_id;

Here current_supplier_id comes from the server-side session, not from an arbitrary form field. For editing or downloading a document, the same check is applied to the specific action and object. If the product needs to share an invoice with an accountant at another company, that exceptional right must be expressed as an explicit access rule, not by removing the owner check for everyone.

Observable result. A supplier sees their own invoice; an attempt to fetch another supplier's record does not return its contents. If the mere existence of someone else's invoice is sensitive, the response for "no such record" and "no permission" can be identical. A protected internal log keeps the minimum information needed to investigate the refusal.

The driver passes invoice_id and current_supplier_id as separate parameters; the binding syntax depends on the driver, but the application must not build SQL by concatenating text. The same check must cover not only reading but also editing and downloading the document.

Why this is better. The solution checks exactly the rule "this user may read this invoice", regardless of buttons or how complex the number is. A negative test must confirm that another supplier cannot read, change or download the document. A random number may reduce accidental guessing, but it is not a permission.

Limits and alternative. A check inside the database query is simple for a direct "invoice — supplier" relationship, but a complex policy may require a centralised authorisation service or explicit sharing relationships. Either way, the server must decide for every action, and the team must show that the critical paths go through that decision. (OWASP Insecure Direct Object Reference Prevention Cheat Sheet)

Keep data separate from commands and code

Input validation checks whether a value belongs to the expected domain: for example, that a date exists, a quantity is non-negative, and a file's format and size are acceptable. It is useful, but it is not a universal way to make text safe everywhere. The same value may end up in a database, a HyperText Markup Language (HTML) page, a request URL or a log, each with different rules.

Injecting commands into a database query

Structured Query Language (SQL) describes commands to a relational database. SQL injection happens when an application assembles a command by concatenating text in a way that lets user input become part of the command itself. The reliable default defence is a parameterised query: the structure of the command is defined separately, and the values are passed through the parameter-binding mechanism of the driver or framework. Simply escaping all input is a fragile substitute for this separation. (OWASP SQL Injection Prevention Cheat Sheet)

Parameterising values does not always let you substitute a column name or a sort direction. Such structural fragments must be chosen from a limited list defined by the application; do not assemble them from an arbitrary user string. And checking the right to a record remains a separate layer: a query that is safe from SQL injection can still read someone else's invoice if it lacks an owner condition.

Displaying data in the browser

Cross-Site Scripting (XSS) is a class of flaws in which the browser interprets untrusted data as active page content. The defence rests on context-sensitive output encoding: data becomes text rather than code, according to the rules of the place where it is inserted. Plain text, an attribute, a link address and script code each need different handling. Prefer the template engine's automatic escaping and the browser's safe text interfaces; avoid inserting arbitrary markup through "unsafe" functions.

If the product supports formatted content, allow a narrow set of elements and attributes and apply a proven sanitiser built for that specific context. There is no universal tool. A Content Security Policy (CSP) can act as an additional barrier, but it does not by itself fix an unsafe way of outputting data. (OWASP XSS Prevention Cheat Sheet)

Requests the browser sends automatically

Cross-Site Request Forgery (CSRF) exploits the fact that a browser may automatically attach a cookie to a request to a site where the user is already signed in. If the site relies on that session alone, a third-party page can try to make the browser perform an unwanted action on the user's behalf.

The defence depends on the authentication method and the client: use the framework's built-in mechanism or a proven CSRF token; where needed, check the request origin and restrict cookies with the SameSite attribute. These measures are required for every request that changes state; read requests must not change data. XSS and CSRF are different flaws: XSS can bypass many CSRF defences, so both must be fixed. (OWASP CSRF Prevention Cheat Sheet)

Limit the server's network trust

Server-Side Request Forgery (SSRF) occurs when a user influences the address to which the server makes a network request, and the server can reach resources the user cannot reach directly. Examples of features with such a path: importing an image from a link, creating a webhook, or fetching data from an integration. A Uniform Resource Locator (URL) can point to an external site, an internal service or another protocol; what matters is that the server makes the request. OWASP recommends starting with a narrow list of trusted addresses when the product does not need to reach any site at all. (OWASP SSRF Prevention Cheat Sheet)

Worked example 2: importing an image from a URL

Situation. A user pastes an image address, and the server downloads it to create a thumbnail. The decision "allow any link as long as it is HTTP" lets the server connect to a network address chosen by an outside user.

Decision and action. First find out whether server-side fetching is needed at all: perhaps the user can upload the file in the browser or choose a partner domain. If importing from an arbitrary URL is necessary, allow only the expected schemes and check the address, and every IP address it resolves to, immediately before connecting. Configure the client or a controlled proxy so that it connects to exactly the IP address that was checked, rather than looking the name up again. Check every new address after a redirect, or disable redirects. The Domain Name System (DNS) can return a different address over time, so checking the name once is not enough. If pinning the checked IP address is impossible, an egress network filter must control where the connection actually goes.

Isolate the fetching service from internal networks, set a short timeout and a small size limit, and check the file's real type. Do not pass the user's cookies, internal service headers or application secrets to the external host.

Observable result. An image from a permitted source passes the limits, is stored as an untrusted file and is displayed only after its type and size have been checked. An internal or disallowed destination is rejected, and an overly large or slow file does not consume unlimited resources. A separate log records the reason for refusal without the full URL, if that could contain private parameters.

Why this is better. Layered restrictions reduce risk even if the application-level check misses an error.

Limits and alternative. A domain allow-list does not suit a service that must import from any public site. In that case the validating parser must interpret the address exactly as the real network client does, and a low-privilege service must have restricted network egress. An application-level check does not remove a bug in a library or a new bypass technique.

In May 2026 the GitHub Advisory Database described an SSRF in Open WebUI (CVE-2026-45400): versions up to and including 0.9.4 were vulnerable, and 0.9.5 contains the fix. The URL validator and the network library interpreted special characters differently, so an address that looked external could direct the request to an internal target. PR #24534 and the release notes confirm that such characters are now rejected. The sources confirm the report and the fix, but not exploitation in a real installation; this patch also does not prove that every SSRF path has been closed. (GitHub Security Advisory GHSA-8w7q-q5jp-jvgx; PR #24534; Open WebUI v0.9.5 release notes)

Manage dependencies and resources

An application inherits the risks of its frameworks, libraries, third-party scripts and infrastructure settings. A dependency inventory and scanners help find a problem, but you still have to check whether the component is in the deployed build, whether the vulnerable function is reachable, which fix is available and what an update will change. An outdated or unused library can also be executed indirectly or wired in later. For a third-party script in the browser, find out which code runs on behalf of the page, whether that vendor is needed and how its updates are reviewed. (OWASP Vulnerable Dependency Management Cheat Sheet)

Worked example 3: a library fix with a breaking change

Situation. A scanning tool reports that a document-preview library has a known vulnerability; the vendor has released a fixed version. Suppose the new release also changes the structure of the output that the importer consumes. This is a generalised teaching scenario, not a report on a specific incident.

Decision and action. The team checks whether the library is part of the deployed build and whether the vulnerable path is reachable by untrusted users. It reads the advisory and the release notes, updates the dependency in a separate change and tests the import. If the fixed version breaks compatibility, the team temporarily restricts or disables the feature, assigns an owner and a review date, and prepares the migration. It also checks the package source, the pinned versions and the reliability of the update supply channel.

The decision is neither "update everything immediately" nor "the scanner is wrong". Check whether the vulnerable function is actually reachable, give the temporary restriction an owner and a review date, and record the reason for the choice. For a third-party browser script, separately determine which code runs on behalf of the page, whether the vendor is needed and how the team controls its changes.

Observable result. The team disables document preview while adapting the importer to the renamed field. After testing document reading, the expected refusals and the dependency version, it ships a compatible fix and restores the feature on the fixed version. The changelog records the library version and the closing of the temporary restriction.

Limits and alternative. If the advisory describes a critical path to sensitive data, isolation may not be enough: you must shut that path down or deploy the fix urgently under the emergency release procedure. If the alert does not match the actual component or execution path, that must be demonstrated with the inventory and configuration, not simply marked as a false positive.

Limit resource consumption

Resources have limits too. A request can be authenticated and permitted yet still create an excessive amount of computation, downloads, queue jobs or spending on an external service. Limit request and file sizes, execution time, the number of parallel jobs and the frequency of expensive operations. Limits should come from product measurements and the threat model: there is no single requests-per-minute figure for every system. Also check the side effect of a defence: a hard sign-in lockout can let someone lock the victim out. (OWASP Denial of Service Cheat Sheet)

Minimise data and protect logs

Security and privacy depend on how much data the product collects, who can read it, how long it is kept, and whether it is actually deleted from live systems and backups according to a defined policy. Collect only the data you need, restrict access by role and task, set retention periods and explain the deletion path. Data on disks and in backups may need encryption at rest and separate control over access to the keys; encryption on its own does not replace application-level authorisation. (OWASP User Privacy Protection Cheat Sheet) Legal obligations depend on the country, the type of data and the context; a ticked checkbox does not prove compliance with a particular legal regime.

A technical log helps investigate a failure, a suspicious action or a release error, but it must not become a store of secrets and unnecessary personal data. Keep the context needed for an investigation, and restrict access and retention. Show the client a safe explanation without a stack trace, an SQL query or an internal path. (OWASP Logging Cheat Sheet; OWASP User Privacy Protection Cheat Sheet)

Do not log passwords, session tokens, keys, full payment details or unnecessary personal data. A detailed trail should help reconstruct a decision and identify who performed it, but only those who need the logs for their work should be able to read them.

Verify claims, not the presence of a tool

Verification must show which paths were tested and what happens at the permission boundary. For a critical feature, test both outcomes: the owner sees their record while another organisation can neither read nor change it; the server rejects an expired session even when the browser still holds the cookie; a wrong file type and an oversized import are stopped before they consume unlimited resources.

Code, dependency and configuration scanners find problems only within their rules; they can miss an authorisation error or a problem in how components interact, or point at a vulnerable path that is not reachable. Verify such signals and document the conclusion. OWASP ASVS helps agree on requirements and the level of verification, but neither the standard itself nor a green scanner report confirms the security of the whole product.

A signal that does not match the actual execution path must also be justified with the inventory and configuration, not simply hidden.

A response plan for a confirmed flaw must name an owner and the next action: restrict or disable the vulnerable path, notify the right team, keep records sufficient for an investigation, deploy the fix and verify that the feature has been restored. The order depends on impact and business context; revoking access or rolling back code does not undo data that may already have been exposed. The US National Institute of Standards and Technology (NIST), in Special Publication (SP) 800-61 Revision 3 (2025), treats incident response as part of a broader cybersecurity risk-management cycle. (NIST SP 800-61 Rev. 3)

Ask the team for verifiable evidence, an owner and the limits of coverage, not for the name of a fashionable technology: which test rejects another supplier's invoice, which addresses the importer cannot reach, and when will the temporary disabling of the vulnerable feature be reviewed?

Requests made by agents must pass the same server-side access checks as any other client. The additional risks of untrusted content and agent tools are covered in AI agent security.

Sources and further reading

All web sources below were checked on 24 September 2026. The OWASP Cheat Sheet Series guides are living pages without a fixed version; if you reuse them, verify their current content. ASVS is cited with its version number because OWASP itself warns that requirement numbers may change.

  1. OWASP Foundation, Application Security Verification Standard (ASVS), 5.0.0. An open basis of verifiable requirements for designing and testing web applications. Project page.
  2. OWASP Cheat Sheet Series, Threat Modeling Cheat Sheet. Describes assets, data flows, trust boundaries and the repeatable questions for a threat model. Link.
  3. OWASP Cheat Sheet Series, Authorization Cheat Sheet. Supports the distinction between authentication and authorisation, deny-by-default and checking permissions on every request. Link.
  4. OWASP Cheat Sheet Series, Insecure Direct Object Reference Prevention Cheat Sheet. Recommendations for protecting access to specific objects. Link.
  5. OWASP Cheat Sheet Series, Session Management Cheat Sheet. Cookie attributes, session termination and revocation. Link.
  6. OWASP Cheat Sheet Series, Transport Layer Security Cheat Sheet. The limits of transport protection, HTTPS, cookies and caching of sensitive responses. Link.
  7. OWASP Cheat Sheet Series, SQL Injection Prevention Cheat Sheet. Separating query code from data, and parameterised values. Link.
  8. OWASP Cheat Sheet Series, Cross Site Scripting Prevention Cheat Sheet. Contextual output encoding, safe output interfaces and the role of additional measures. Link.
  9. OWASP Cheat Sheet Series, Cross-Site Request Forgery Prevention Cheat Sheet. Protecting state-changing requests depending on the authentication method and the browser. Link.
  10. OWASP Cheat Sheet Series, Server-Side Request Forgery Prevention Cheat Sheet. The limits of safely fetching external resources, and protection at the application and network levels. Link.
  11. GitHub Advisory Database, GitHub Security Advisory (GHSA) GHSA-8w7q-q5jp-jvgx / CVE-2026-45400. The report was published in the Open WebUI repository on 10 May and the GitHub Advisory Database entry on 14 May 2026. Version ranges and a description of the mismatch between URL-parsing modules in Open WebUI. Link.
  12. Open WebUI, Pull Request #24534, May 2026. Primary confirmation of the change to URL validation for a specific class of mismatches. Link.
  13. Open WebUI, Release v0.9.5, May 2026. The release notes confirm that the fix is included. Link.
  14. OWASP Cheat Sheet Series, Vulnerable Dependency Management Cheat Sheet. Inventory, assessment, remediation planning and handling dependency risk. Link.
  15. OWASP Cheat Sheet Series, Denial of Service Cheat Sheet. Resource limits, request sizes and rate limiting as part of availability. Link.
  16. OWASP Cheat Sheet Series, Logging Cheat Sheet and User Privacy Protection Cheat Sheet. Safe logging and data minimisation. Logging; privacy.
  17. National Institute of Standards and Technology, SP 800-61 Rev. 3, Incident Response Recommendations and Considerations for Cybersecurity Risk Management, April 2025. The core source for placing incident response within the risk-management process. Link.