Digital Engineering/AI Product Assurance/AI Application Security Audit
Find the security gaps in your AI-built application before somebody else does
AI-built applications are rarely unsafe because a model wrote something reckless. They are unsafe because a control was applied on Tuesday and forgotten on Thursday, and nobody has read the whole system since. We assess yours the way an attacker and an enterprise security reviewer would, then hand you located, classified, evidenced findings you can act on this week.
Generated code fails on consistency, not on competence
Ask a current model to write a login flow and you will usually get a decent one. Modern hashing, sensible session handling, parameterised queries. Line by line, most AI-generated code is more careful than the hand-written code it replaced.
Security is not judged line by line. It is a property of the whole system, and the whole system is what nobody held in mind while it was being built.
Each session starts from nothing.
A generator sees the open file and the instruction you typed, not the twelve routes written a fortnight ago, not the convention you settled on for tenant scoping. So every session re-decides. Those decisions are reasonable individually and are not, collectively, a security model.
The gap is in the additions.
The original build is usually internally consistent, because it came from one sitting and one instruction. The exposure arrives with the fourteen features added afterwards: the admin endpoint, the CSV export, the webhook receiver, the internal tool nobody counted as part of the product.
Nothing forced a review.
In a team, another engineer checks that a change fits the system’s assumptions before it merges. When the reviewer wrote the prompt and the code arrived working, that check does not happen.
How we control what we assess and what we generate
Method is the part most security suppliers keep vague. Ours is published, because a buyer who cannot see how a finding was produced cannot judge whether it is worth acting on.
Static analysis on every codebase, tuned, never at defaults. Every engagement runs Semgrep, CodeQL and SonarQube. What matters is the day of work before those results are worth reading.
Point Semgrep’s default registry rules at a typical AI-built Next.js application and you will have a few thousand results before lunch. Almost all are true statements about generic code and false statements about yours: a dangerouslySetInnerHTML fed by a compile-time constant, a hard-coded string that pattern-matches as a credential and is a Stripe test key in a fixture, a SQL-shaped template literal your ORM never executes as SQL. The cost is not the wasted hour. It is that a register of two thousand findings has the same practical value as an empty one: nobody triages it, the four results describing real exposure are indistinguishable from the noise, and within a week the team has learned to dismiss the scanner rather than read it. That is what makes defaults worse than no scan at all: a scan you ignore still lets you tell your next customer that you scan.
Defaults also miss in the other direction, which is the half people forget. An off-the-shelf ruleset knows nothing about your conventions. It does not know that authorisation here is enforced by a withTenant wrapper, so it cannot notice the handler that omits it, and it does not know that your renderMarkdown helper is the sink that matters. Generic rules cannot find a gap in a control they have never heard of.
So we teach the tools your application first. Semgrep gets rules written against your framework. A rule asserting that every handler under /api/ is wrapped by your authorisation helper will find the one that is not, and no public ruleset can write that rule for you. CodeQL gets custom sources and sinks, so taint tracking follows data through your own request-context helpers instead of stopping at the first unfamiliar function. SonarQube runs on a pruned profile. Findings that survive tuning are confirmed by an engineer against the code path before reaching your register.
Standards as a reference frame, not a claim. Findings are assessed against the OWASP Application Security Verification Standard and the OWASP Top 10, with secure development lifecycle practice referenced to the NIST Secure Software Development Framework. Each finding is tagged to the control area it relates to, so remediation maps onto something external rather than onto our preferences. To be exact: we identify gaps relevant to these standards and describe what closing them involves. We do not certify compliance against them, and no engineering firm can.
OWASP ASVS
Application Security Verification Standard
OWASP Top 10
The most critical web application risks
NIST SSDF
Secure Software Development Framework
Dependency and licence provenance. We trace where each package actually came from, not only what the manifest declares: registry source, maintainer history, whether a name resolves to what you assume. Alongside that: vulnerabilities with reachability assessed rather than counted, transitive version conflicts, and licence obligations traced while a copyleft dependency inside a distributed binary is still a technical question and not yet a legal one.
Where we generate code, the same controls apply to our own output. During remediation or build work our engineers use AI tooling under governed conditions: an approved model and IDE list with each vendor’s data-retention terms recorded, and no tool that trains on submitted code on that list. Prompts for security-relevant work name the weakness classes that apply, referenced to OWASP categories and MITRE’s CWE list: CWE-89 for anything constructing a query, CWE-79 wherever generated output reaches a template, CWE-639 on anything resolving an object by identifier. Generated code passes automated scanning before human review, so review time goes on judgement rather than on catching what a tool catches. And agents run with explicit stop conditions: an agent escalates rather than improvises when work would touch an authentication or authorisation path, add or upgrade a dependency, alter an IAM policy, security group or CORS configuration, rewrite a data migration, or write to any path matching our secrets patterns.
The failure patterns specific to AI-generated code
These are not hypothetical. They are what we find, in roughly this order of frequency.
Authorisation that holds in most places
Authentication is almost always present and usually fine. Authorisation is where it breaks. Twelve routes check that the requesting user owns the record; the thirteenth, added in a later session, checks only that a session exists. Object identifiers are sequential integers, so /api/invoices/4192 becomes /api/invoices/4191 and returns another tenant’s document. Nothing is broken from the scanner’s position: the route never claimed to need a check.
Secrets committed because nothing modelled environment separation
A generator asked to make an integration work will inline the key, because inlining it works. We routinely find live keys in committed .env files, in client bundles where NEXT_PUBLIC_ was the fastest way past an undefined variable, and in git history after someone rotated the file but not the repository.
Validation exactly where it was requested
Zod on the create endpoint because the prompt mentioned validation; nothing on the update endpoint written the following week. Client-side checks with no server counterpart. Type annotations mistaken for runtime guarantees at the boundary where untrusted JSON arrives.
Insecure defaults inherited from training-era patterns
Generated code reproduces the idiom that was common when the corpus was written: MD5 or unsalted SHA-256 for passwords, cookies without HttpOnly, SameSite or Secure, CSRF protection disabled to get a form working, JWT verification that accepts the algorithm the token declares, TLS verification switched off to clear a local error and never switched back.
Dependency hallucination and slopsquatting
Models invent plausible package names. Attackers now register those names ahead of you. An install command copied from a chat transcript can pull a package that exists only because someone predicted the hallucination, which is why we check provenance, not just versions.
Permissions written wide to make something work
Access-Control-Allow-Origin: * alongside credentialed requests. IAM roles carrying s3:* on * because a narrower policy failed once. Storage buckets public because that was how the upload preview started rendering. Security groups open to 0.0.0.0/0 on a database port.
Prompt-injection exposure where the product itself calls a model
If your application feeds user content, uploaded documents or scraped pages into an LLM, that input is instruction. We assess whether model output is treated as trusted, whether tool calls the model can trigger are scoped to the invoking user’s permissions, and whether a document uploaded by one customer can steer a response rendered to another.
What the assessment covers
The Application Security dimension of the Noseberry Product Assurance Framework, at full depth rather than the summary level an AI Code Audit provides. Nine areas, each evidenced against the code and configuration in front of us.
Authentication and session handling
Credential storage, recovery flows, multi-factor coverage, token issue and expiry, session invalidation on logout and on privilege change.
The authorisation model
Whether one exists as a model at all, whether it is enforced centrally or restated per route, and every path where it is absent or weaker than its neighbours.
Input handling and output encoding
Server-side validation at every entry point, injection surfaces across SQL, NoSQL, command and template contexts, file uploads, and encoding wherever untrusted data reaches a rendered surface.
Secrets and configuration
Where secrets live, how they reach running code, whether environments are separated, and what is recoverable from git history.
Data exposure and tenancy isolation
What each API response returns versus what the interface displays, and whether tenant scoping is enforced at the query layer or assumed above it.
Dependencies and supply chain
Inventory with provenance, reachability-assessed vulnerabilities, transitive conflicts, licence obligations.
Cloud, network and identity
IAM policies and role boundaries, storage exposure, network reachability, and logging sufficient to reconstruct an incident.
LLM-facing surfaces
Injection exposure, tool and function-call scoping, output handling, and what a model can reach on a user’s behalf.
Secure-SDLC practice
How change is reviewed and released, and where AI tooling sits inside that, referenced to NIST SSDF.
Runtime testing against live production infrastructure is out of scope. That is a penetration test.
Who this is for
Teams with an enterprise deal waiting on a security review.
A questionnaire has arrived, and the deal is blocked on answers nobody in the building has.
Founders whose product holds data that matters.
Health, financial, identity, children’s data, or anything belonging to a business customer. The threshold for “good enough” moved the day you accepted it.
Engineering leaders after an incident or a near miss.
Something was exposed or nearly exposed, and the question is no longer whether to look but how thoroughly.
Teams beginning a certification programme.
You are heading towards SOC 2 or ISO 27001 and want the application-layer gaps found before an auditor’s readiness assessment charges you to find them.
Products that call an LLM.
You built an AI feature into your application, and the questions it raises are not covered by your existing review process.
When to book this rather than something else
Timing matters, because a security assessment is most valuable while its findings can still change a commitment.
Before the questionnaire is due.
Six weeks of lead time turns a findings register into a remediation plan with completed items on it. Six days turns it into a list of things you have to disclose.
Before your first regulated or enterprise customer signs.
Security obligations are cheaper to meet before you are contractually bound to them.
After a product you did not build in one piece has grown.
If a working application has since gained ten or fifteen AI-assisted features, the exposure is almost certainly in the additions.
Before a penetration test, not instead of one.
A pentest spending its fixed days rediscovering committed secrets is expensive noise. Clear what an audit finds, then buy the test, then get a report worth showing a customer.
How the assessment runs
Threat context
day 0
A 45-minute call establishing what data the product holds, who the realistic adversary is, which surfaces are internet-facing, and which deadline the assessment serves. A consumer note-taking app and a B2B application holding payroll data deserve attention on different surfaces. NDA executed before any access is granted.
Tooling and tuning
days 1–2
Repository ingest, then the tuning pass described above: custom Semgrep rules, CodeQL sources and sinks matched to your helpers, SonarQube on a pruned profile, secrets detection across full git history rather than the working tree, and a dependency and licence inventory.
Manual security review
days 2–7
Engineers work the authorisation model route by route, follow tenant scoping to the query layer, trace untrusted input from every entry point to every sink, read the IAM and network configuration, and exercise LLM-facing surfaces. This is where the findings that block deals come from, and it is not automatable.
Classification and impact
days 7–8
Each finding gets a technical severity, a business-impact statement, a reproduction path, a remediation recommendation and an effort estimate. Anything Critical has already reached you: we report those the day we confirm them.
Report, walkthrough and evidence pack
days 8–10
A written report, a prioritised remediation plan, and a working session with your engineers. Where an enterprise review is the driver, we also brief your commercial lead on what can accurately be said.
Typical elapsed time is ten working days for a single-product codebase. Multi-repository estates, microservice architectures and products with significant LLM surface run longer and are scoped individually. You do not wait for a silent fortnight followed by a document. Anything Critical reaches you the day we confirm it.
What you receive
- A security assessment report covering all nine areas in scope, stating what was examined, what was found, and what was checked and found sound. A reviewer’s list of what they confirmed is as useful to a buyer as the list of what they broke.
- A findings register in which every issue carries a location down to file and line, a reproduction path, a technical severity, a business-impact statement, a remediation recommendation and an effort estimate.
- A control coverage map showing which OWASP ASVS control areas and OWASP Top 10 categories the findings relate to, and which areas were examined without material gaps.
- A dependency and licence inventory listing every direct and transitive package, its source, reachability-assessed vulnerabilities, and any licence obligation carrying a commercial consequence.
- A prioritised remediation plan sequenced by exploitability and blast radius, so the first fortnight of work removes the most exposure rather than the most items.
- A secure-SDLC gap summary referenced to NIST SSDF, covering how change is reviewed and released and where AI tooling sits inside that.
- A security questionnaire evidence pack mapping our findings and your existing practice onto the questions enterprise buyers ask.
How security findings are classified
Every finding carries a technical severity and a business consequence. They are not the same measurement, and conflating them is how remediation ends up in the wrong order.
CVSS base score
Where a finding maps to a known CVE we record the published CVSS v3.1 base score and vector. Where it does not, and most application-logic findings do not, we score it on the same dimensions, so severities stay comparable across the register. A base score alone will mislead you, because base scores are environment-blind by design.
The class we assign
A CVSS 9.8 in a build-time dependency that never executes in production matters less than a CVSS 6.5 object-level authorisation flaw returning another tenant’s records to anyone who can count. So the class is set by exploitability in your deployment, blast radius and business consequence, with the technical severity recorded alongside.
Class
What it means here
Expected response
Reachable from the internet, exploitable without privileged access, exposes customer data, money or availability.
Same week, before the next release.
Exploitable with a condition attached: an authenticated account, a specific sequence, a known internal path.
Inside the current quarter.
Real weakness, limited reach or a meaningful barrier to exploitation. Hardening gaps sit here.
Planned work, sequenced with delivery.
Defence in depth. No current exposure; reduces the cost of a future mistake.
Take it while the surrounding code is open.
Answering enterprise security questionnaires and procurement reviews
Most of our security engagements are bought because a customer’s security team asked something the founder could not answer. It is worth being specific about what they ask.
Whether it arrives as a SIG Lite, a CAIQ, a VSAQ export or a spreadsheet somebody’s security team wrote themselves, the application-layer questions are consistent. Do you perform static analysis, with what tooling, at what frequency, and who reviews the output. Do you maintain an inventory of third-party components, and how quickly are disclosed vulnerabilities triaged and patched. How are secrets stored and rotated. Is production separated from non-production, and can non-production reach customer data. How is customer data segregated between tenants, and is that enforced technically or by convention. Is code reviewed before release by someone other than its author. When was your last penetration test, and can we see the report. What is your incident response and notification process. And, increasingly, a block on AI: which coding assistants your engineers use, whether your code goes to a vendor that trains on it, and what review applies to generated code before it ships.
Nobody expects a twelve-person company to have the answers a bank has. What loses deals is a supplier who cannot describe their own position, because the reviewer’s next question is what else you have not looked at.
The assessment produces the artefacts those answers cite: a dated findings register, a dependency and licence inventory serving as the component inventory the questionnaire asks for, evidence of static analysis with named tooling, a secure-SDLC gap summary referenced to NIST SSDF, a control coverage map against OWASP ASVS, and a remediation plan with owners and dates. We do not complete the questionnaire for you, and we will not tell you to write anything you cannot evidence. We supply the material, and join the reviewer’s call if it helps.
What this is not
This is not a penetration test.
We assess source code, configuration and design. A penetration test attacks a running system from the outside, without full source visibility, to demonstrate what is exploitable in practice. The two find different things: we find the missing check on a route a tester never discovers; a tester finds the misconfigured WAF and the exposed staging host the repository does not describe. Buy a penetration test when a contract requires one, when you need an independent tester’s report to hand to a customer, or when your deployed infrastructure is the thing in question rather than your code.
This is not a certification and we are not a certification body.
A SOC 2 report is issued by a licensed CPA firm after an examination period. ISO 27001 is certified by an accredited certification body. Neither is something an engineering assessment can produce, and any supplier suggesting otherwise is describing something that does not exist. What we do is identify gaps relevant to the control areas those processes examine, which supports readiness for them and makes the auditor’s engagement shorter, but the certificate comes from the auditor.
This is not a bug bounty.
A bounty programme buys breadth and continuity from many researchers over time, and it works well on a hardened baseline. Running one against an unhardened AI-built application means paying market rate for findings a tuned scanner would have handed you in an afternoon, in public, on a clock you do not control.
How we handle your source code and your findings
Security buyers ask harder questions about this than anyone else, and they should.
Access is minimal, named and time-bound.
Read-only repository access for the branches in scope, plus read-only cloud console access where infrastructure is reviewed. Every reviewer is named in the engagement note before receiving anything, and access is withdrawn on delivery. Write access never forms part of an assessment.
No production data, ever.
We work from schema, data classification and flow. If a reviewer on our side asks for a database dump or live credentials, refuse it and tell us. That is a mistake on our part, not a requirement of the method.
Analysis can run inside your perimeter.
Where your policy or your customer’s contract demands it, the tooling runs in your environment and only findings leave.
The findings register is sensitive material in its own right.
A classified, located list of your weaknesses is a map. It is delivered encrypted to named recipients, never pasted into chat or email bodies, and the engagement note carries embargo terms for the remediation window. Source code is deleted on completion unless remediation follows.
What changes afterwards
The questionnaire stops being a blocker.
You answer from documents rather than from optimism, and you can say which items are closed and which are scheduled. Reviewers are untroubled by open items with dates against them. They are very troubled by uncertainty.
Remediation happens in the right order.
Teams fixing by severity label alone tend to spend the first week on the loudest finding rather than the one an attacker reaches first. A register carrying exploitability and blast radius takes that argument out of the room.
Your engineers stop repeating the pattern.
Findings explain the class, not only the instance. Where authorisation was restated per route rather than enforced centrally, the fix is a helper plus a Semgrep rule that fails the build, after which that finding cannot recur, whoever or whatever writes the next route.
You know what you would have to disclose.
If something happened tomorrow you would know which systems held what, whether your logging could reconstruct events, and who you are obliged to tell.
Why Noseberry for this
We publish the method
The tooling, the tuning, the standards we reference and the controls governing our own generated code are all on this page. You can evaluate the approach before speaking to us, and hold us to it afterwards.
We govern our own AI use before we assess yours
Approved model and IDE list, security-explicit prompting referenced to OWASP and CWE, scanning before human review, agent stop conditions. It is hard to take a supplier seriously on AI-generated code risk when they will not describe how they manage their own.
Findings are confirmed, not forwarded
Nothing reaches your register because a tool emitted it. An engineer traces the path and writes the impact. A register you can trust in full beats a longer one you have to re-verify.
We are precise about our limits
We do not certify, and we do not run your penetration test. We say so on the page rather than in the small print.
One framework across the cluster
This reports into the same six dimensions as every other Noseberry engagement, so a later production readiness or architecture review extends the picture rather than restarting it.
Not sure this is the assessment you need?
Send us the repository and whatever the security review asked. We will tell you plainly whether this assessment answers your question, or whether a penetration test or a readiness review is the better spend given your deadline.
Frequently asked questions
Plenty of it is already running safely in production. Line by line, modern models produce code at least as careful as the average hand-written equivalent. The exposure comes from what no model holds: the shape of the whole application across dozens of separate sessions. Controls end up applied in some places and absent in others, and nobody has read enough to notice. That is fixable, and fixing it rarely means rewriting. It means establishing the security model once, enforcing it centrally, and verifying it holds everywhere.
No. We work from source code, configuration and architecture with full visibility. A penetration test attacks a running system from outside, usually without that visibility, and shows what is exploitable in practice. Source review finds the authorisation check missing from one route in forty; a tester finds the exposed staging environment your repository never mentions. Neither substitutes for the other. If a contract requires an independent tester’s report you need a penetration test too, and it is better value once this work has cleared the obvious findings.
No, and nobody selling engineering services can make you SOC 2 anything. A SOC 2 report is issued by a licensed CPA firm following an examination period; ISO 27001 certification comes from an accredited certification body. What this assessment does is identify gaps relevant to the control areas those processes examine: change management, access control, secure development practice, vulnerability handling. That supports readiness and usually shortens the auditor’s engagement, because the application-layer work is already evidenced. The certificate comes from the auditor.
Ten working days end to end for a single-product codebase: scoping on day zero, tooling and tuning across days one and two, manual review through the middle, classification and reporting at the end. Multi-repository estates, microservice architectures and products with significant LLM surface run longer and are scoped individually. Pricing is quote-led after a scoping call, because effort varies with codebase size and how much infrastructure is in scope. Our fixed-price entry engagement is the AI Code Audit, which covers security at summary depth.
No. We need read-only repository access for the branches in scope, and read-only cloud console access where infrastructure is reviewed. We do not need production database access, customer records or credentials to live systems. Data handling is assessed through schema, classification and flow. Access is granted to reviewers named in advance and revoked on delivery. Where your policy requires it, the tooling runs inside your own environment and only findings leave.
Keep running them. Dependency scanning is valuable and it forms part of our own tooling pass. What those tools give you is a list of packages with published vulnerabilities, largely without reference to whether the vulnerable path is reachable in your application. What they cannot tell you is that authorisation is enforced per route rather than centrally, that one endpoint returns fields the interface hides, or that a package name resolves to something nobody on your team chose. Dependency alerts are one input here, not a smaller version of it.
Yes, and it is one of the areas we find least well covered. We look at whether user-supplied content reaching the model is treated as data when it functions as instruction, whether tool calls the model can trigger are scoped to the invoking user’s permissions or to the application’s, whether model output is encoded before rendering, and whether content uploaded by one customer can influence a response shown to another. We also check what is logged: prompt and completion logs frequently hold data your retention policy never anticipated.
You hear about it the day we confirm it, by an agreed channel, with enough detail to act immediately. We do not hold Critical findings for the report; a fortnight of unnecessary exposure is not worth a tidier document. If the fix is straightforward we usually give it to your engineers alongside the finding. If it points to something structural we say that too, and we will tell you plainly when the safest step is disabling a feature until it is corrected.
Yes, it is your document. Many clients share the summary and control coverage map with an enterprise buyer, since a dated register with a remediation plan reads better than assurances. We produce a shareable version omitting reproduction detail, because a full register is a map of your weaknesses and should not circulate freely. We will not share anything without your written instruction, and we are happy to join a customer’s security call to answer questions about method.
We can, and it is a separate engagement on purpose. Many clients take the register to their own engineers, which is a good outcome and one the report is written to support: every finding carries location, reproduction and effort estimate for that reason. Where you want us to execute, Vibe Code Cleanup and Production Readiness & Hardening pick up directly from the register, with remediation branches held to the same controls we apply to our own generated code.
Get an evidenced answer before your customer asks for one
Send us the repository and whatever the security review asked you. We will come back within two working days with a scope, a price, and a straight view on whether this assessment is the right spend given your deadline.
Related resources
Go deeper with our thinking
From Spreadsheets to a Scalable Platform – building Canada’s Most Tenant- First Coliving System
Read case studyHow to Build a SaaS Product
Read guideThe MVP Development Guide
Read guideBuilding a Digital Engineering Roadmap That Aligns With Business Goals
Read articleEngineering IoT Products: Key Challenges and Best Practices
Read articleNot sure where you stand?
Take a free two-minute readiness scorecard built for your industry.
