Shadow IT: definition, examples and risks
What is shadow IT? The definition from the UK's National Cyber Security Centre, examples (Excel, AI tools), the risks for the business, and why the answer is a tool that fits the work.
Updated on 42 min read
Sébastien Nobour
Founder of DEVEDANOS
PHP is a programming language. According to W3Techs, a service that measures the technologies websites use, it is used, as of October 2026, by 69.3% of the websites whose server-side language is known. On 21 October 2026, the PHP team rushed out new versions of the language. They fix two critical vulnerabilities, which the people who found them named PHP2Shell. With a few requests, and no account or password, an attacker can make the server that hosts a site execute their own code.
If your website or application relies on PHP, the question to ask your host or your provider is simple: which version of PHP do we use, and when does it move to a fixed version? Our article on the October 2026 PHP vulnerability explains who is affected and what to do, in order.
On the same day, GitLab and Node.js also released fixes for serious vulnerabilities. GitLab, a platform that hosts software code and automates its testing and deployment, fixed a vulnerability (CVE-2026-110264) rated 10 out of 10 that, under certain conditions, let someone with no account execute code on self-managed installations. It affected every version since 7.0. GitLab.com, the version hosted by GitLab, had already been fixed.
Node.js, the software that executes JavaScript on servers, released versions that close four high-severity vulnerabilities, one of which, in the decoding of Brotli-compressed data, allows remote code execution. These versions also update the list of trusted certificates, after an intermediate certificate authority of eMudhra was compromised.
If your company hosts GitLab itself, or if its applications use Node.js, the same question applies to these programs: which version do we use, and when does it move to a fixed version?
Some news outlets grouped these fixes and other incidents of the week under the name “Black October”, which appeared overnight on 21–22 October. SecurityToday, a German IT security news site, sees it above all as a peak in disclosures: many of the attacks revealed in those days had started weeks or months earlier.
The rest applies to any application, whatever its language. These vulnerabilities are not the first of this scale, and nothing suggests they will be the last. Three things can be prepared ahead of a vulnerability: what it lets an attacker reach, how long it takes to notice, and how long it takes to fix.
The technical details are grouped in the passages headed “For your technical team”.
Every year, Mandiant, Google Cloud’s threat intelligence team, measures the time between the disclosure of a vulnerability and its first observed exploitation. The average was 63 days in 2018 and 2019, 44 days between 2020 and early 2021, 32 days in 2021 and 2022, then only 5 days in 2023 (Mandiant). In its M-Trends 2026 report, Mandiant estimates that, on average, first exploitation comes seven days before the vulnerability is disclosed. Exploitation is routinely occurring “before a patch is even released” (M-Trends 2026).
VulnCheck, a vulnerability intelligence company, looked only at vulnerabilities with confirmed exploitation. In the first half of 2026, 23.43% of them were exploited on the day they were disclosed, or before. Content management systems, such as WordPress and its plugins, are the most targeted category: a third of these vulnerabilities (VulnCheck). And according to Verizon’s annual report on data breaches, in its 2026 edition, 31% of breaches start with a software vulnerability, ahead of stolen credentials (Verizon DBIR 2026).
Security authorities agree on one point: AI shortens the time available to those who apply fixes. In May, the NCSC, the UK’s National Cyber Security Centre, announced a wave of updates, for vulnerabilities of every severity, because AI, in skilled hands, can exploit the weaknesses accumulated in software “at scale and at pace”. In June, CISA, the US cybersecurity agency, changed the deadlines it sets US federal agencies for applying fixes: they now depend on risk (exposure to the Internet, confirmed exploitation, impact). The shortest deadline is three days. CISA justifies the change by attackers’ use of AI, which “may further narrow” the time defenders have. From this we take one rule: a critical fix is applied on the day it is published, and a delivery approach where every change already goes through the pipeline makes that possible.
AI is also used to write code, and several of these authorities recommend checking it. In March 2026, the NCSC’s chief executive warned that insecure software produced “without human review” could propagate vulnerabilities. The BSI, the German federal cybersecurity agency, points out in a report on coding assistants a risk of over-reliance on these tools and of accepting the code they generate without examining it, especially among junior developers. It recommends that generated code should, as a rule, be checked by developers, with a critical review of the tool’s mistakes and of security risks. For AI agents, the principle of least privilege applies just as it does to the PHP process (details below).
In practice, we advise a team that develops with AI to review every line the tool writes and to put it through the pipeline’s tests, like the rest of the code; to check that a component suggested by AI exists, and who publishes it, before adding it; and to give an agent only the rights its task needs. For an application built with AI, our article “Can you build an app with AI?” explains what the tool does on its own.
An SME or a start-up does not need security researchers on its teams. Finding a vulnerability like PHP2Shell takes specialists, and their research took place before disclosure: eight to ten weeks separate the first report from the fix, according to the timelines of Wiz, a cloud security company, and of Calif, the security research company whose researchers reported the first vulnerabilities to the PHP team (Wiz, Calif). For everything else, the NCSC’s 10 Steps to Cyber Security lists the basic measures, and its Cyber Essentials scheme sets minimum requirements. For those without the expertise, we advise calling on a specialist for an assessment, and appointing a security contact within the company.
Dave Farley is the inventor of the deployment pipeline, often called the CI/CD pipeline. Continuous Delivery means keeping software ready to go to production at any time, through small changes checked automatically. The deployment pipeline is the automated chain that takes each change to the code, tests it, records it and makes it ready to go to production. Dave Farley is the co-author, with Jez Humble, of the book Continuous Delivery, and the author of Modern Software Engineering. In Continuous Delivery Pipelines, he writes that security may need to involve specialists, but that it is “everyone’s responsibility within the team”. Specialists advise; they should not act as “gate-keepers” who approve every release.
What the team that develops and maintains the application can do comes down to four objectives, and none of them requires looking for vulnerabilities:
The sections “Limit what a vulnerability lets an attacker reach” and “Be alerted immediately” cover the first two objectives. The sections on dependencies, on updates and on the delivery approach cover the third, and the section “Website hacked or vulnerability discovered” the fourth. The deployment pipeline also checks every change to the code, to catch the vulnerabilities it would introduce (security testing in the pipeline).
According to M-Trends 2026, the median time between an attacker entering a system and being discovered is 14 days (M-Trends 2026), and the attacker is active all that time: the first two objectives reduce what they can reach and how long they go unnoticed.
A digital service is more than a website. A typical web application has several parts: an entry point that receives requests from the Internet and passes them on, the server that executes the code, a database, backups, and the accounts of the people who administer it all. Each of these parts can be set up so that a vulnerability in one does not give access to all the others. This is called defence in depth.
Give each program only the privileges it needs. The PHP process needs neither to be the machine’s administrator nor to be able to modify the site’s code. The account it uses to connect to the database only needs, according to the WordPress hardening guide, to read and write data; the rights to delete, change the structure or grant rights can be taken away from it, bearing in mind that some WordPress updates need to change that structure. Jez Humble and Dave Farley say so in Continuous Delivery: the default settings of operating systems and databases are not suitable for an application in production; you need firewalls, unnecessary services switched off, and database users with tailored rights.
Make the code impossible to modify from the site. If the PHP process cannot write to the code folders, an attacker who takes control of it cannot as easily drop a web shell there, a small file that lets them come back and control the server from their browser. On a WordPress site, only the uploaded content folder needs to stay writable, and the code editor built into the admin can be disabled.
Segment the network. The database has no reason to be reachable from the Internet: only the application server should be able to connect to it. The NCSC asks for critical components to be more isolated using segregated networks.
Filter upstream, knowing the filter’s limits. A web application firewall, or WAF, inspects requests before they reach the server and blocks those that look like a known attack. The WordPress hardening guide recommends installing one. It has its limits: Cloudflare itself tells customers to apply the fix even with its rules against PHP2Shell. A web application firewall buys time; it does not replace the fix.
Send security headers, and check them on the live site. With every page, the server can tell the browser what it may do with it: use only encrypted connections, refuse to let another site display the page in a frame, load scripts only from the expected addresses. OWASP, the reference foundation for web application security, recommends these headers, and points to Mozilla Observatory to check them on the production site. The most demanding of them, the Content Security Policy (CSP), limits the scripts a page can run: code slipped into a payment page to copy card numbers then has a harder time running. OWASP describes it as “an effective second layer of protection”, not to be relied on alone. On an existing site, it is introduced in stages, first in report-only mode, where the browser reports what it would block without blocking anything.
Take secrets out of the code. Passwords and access keys to other services (payment, email sending, storage) should not be written in the code files. MITRE ATT&CK recommends a policy that forbids storing passwords in files. Placed in the server’s environment variables or in a secrets vault, they remain readable by PHP while it runs: that does not protect them if the PHP process is taken over. What you gain, in our view, is that they are no longer in the code’s history or its backups, and that they can be changed without touching the code. That matters on the day they all have to be replaced.
Decide where secrets live. Pipeline and production secrets belong in the protected variables of the continuous integration platform, or in a secrets manager: GitLab asks for tokens and passwords to be stored in the project settings, never in the file that describes the pipeline. On a developer’s machine, we advise keeping no secret in plain text in a file: the password or secrets manager hands it to the program when the program runs; without one, Jez Humble and Dave Farley advise keeping it encrypted. OWASP recommends separating production secrets from development ones, and giving each only the minimum rights: a developer works with development credentials, which do not open production. A token that is no longer used is revoked at the service that issued it, rather than staying valid in a forgotten file.
Protect user and administrator accounts. An attacker does not always need a vulnerability: a reused password is enough. The NCSC asks for multi-factor authentication on accounts for online services, to protect against password guessing and theft. In practice, we advise a password manager, so that everyone has a different password for each service, and two-factor authentication on the accounts that give access to production, hosting and code.
Forbid manual changes in production. In Continuous Delivery Pipelines, Dave Farley sets a goal: “We should aim to eliminate human write access to production systems.” Every change goes through the deployment pipeline. In Continuous Delivery, the two authors add that production must be locked down against people outside the company and inside it alike, operations teams included. Without that, when something goes wrong, nobody knows any more who did what, or when.
Keep offline backups, and test them. A backup reachable from the compromised server can be encrypted or wiped along with the rest. The NCSC asks for up-to-date, isolated, offline backup copies of all important data, and notes that practised backups let you restore important data faster (10 Steps: data security). A backup that has never been restored has not proved that it works.
user directive, which is mandatory (php.net). Settings set with php_admin_value and php_admin_flag cannot be overridden with ini_set(). Do not expose PHP-FPM on an address reachable from outside.expose_php = Off, display_errors = Off, allow_url_fopen = Off, allow_url_include = Off, open_basedir, disable_functions (system, exec, shell_exec, passthru, proc_open…), and secure, httponly and use_strict_mode session cookies. But the PHP documentation itself warns that disable_functions “can be circumvented” and that open_basedir “is just an extra safety net, that is in no way comprehensive”, and it does not restrict access to Unix sockets. These settings make the rest of an attack harder; they do not prevent it, and PHP2Shell is triggered before the application runs.Strict-Transport-Security, Content-Security-Policy, X-Content-Type-Options: nosniff, frame-ancestors in the CSP (or X-Frame-Options), Referrer-Policy, Permissions-Policy. The CSP starts as Content-Security-Policy-Report-Only, while the legitimate scripts are listed.Once the defences are in place, you still need to be warned when they are breached. The goal is threefold: know that something abnormal is happening, cut off access, then find where the attack comes from. In Continuous Delivery, Jez Humble and Dave Farley ask that, when something goes wrong, the operations team be “informed immediately” of the incident, and have the tools to track down its cause. They also point to a common mistake: swallowing errors instead of logging them, which prevents them from being detected.
A monitoring solution watches specific signals, and its logs are kept somewhere other than the server being watched. Operations teams follow the state of the servers continuously on dashboards, such as Grafana or Kibana, which bring together metrics and logs and fire an alert when a threshold is crossed. Here are the signals these alerts should watch.
The web server starts a program. A web server serves pages; it has no reason to start a command interpreter or a download tool. When it does, a web shell is often in use (MITRE ATT&CK).
The server connects to unknown addresses. Cryptocurrency mining software, a remote access tool or a data leak all need outbound connections. We advise blocking the server’s outbound connections by default, except to the services the application needs: this also limits the use of these tools.
A code file changes. In production, the code only changes during a deployment. A new .php file in the site’s folders, outside a deployment, is a sign of intrusion. WordPress recommends monitoring file integrity, and points out that an attack always leaves traces in the logs or the file system.
A new administrator account appears. The NCSC asks you to review user accounts for unnecessary privileges on a regular basis. An administrator account created outside any procedure is a signal to act on.
Errors pile up. We advise logging the errors of web services (403, 404 and 500 errors) and unexpected shutdowns.
Keep the logs off the server. An attacker who controls the server can erase their tracks in the logs stored on it. The NCSC asks for logs to be protected from tampering, and suggests drawing them into a centralised location (10 Steps: logging and monitoring).
A few open source tools, given as examples:
/etc (Falco documentation).An application is not written entirely by the people who develop it. It relies on components published by others, its dependencies, which tools install and update: Composer for PHP, npm or pnpm for JavaScript. And it runs on an environment, PHP itself, supplied by the server’s operating system, by the host or by the image used to deploy it.
In Continuous Delivery, Jez Humble and Dave Farley are categorical: “your build system should always specify the exact version of the external libraries that you use.” Without it, they write, you cannot reproduce what is in production. In our view, you cannot know whether you are exposed to a vulnerability either.
Fewer components installed means fewer possible vulnerabilities: OWASP asks you to remove unused dependencies. And a component abandoned by its author will never get another fix: it gets replaced.
When a project accepts “any version from this one onwards”, a newly published version enters the application at the next update, without anyone having chosen it. This is currently npm’s default setting (npm), and Composer recommends it for libraries meant to be reused by other projects (Composer). The notation is detailed in the “For your technical team: dependencies” box below.
Not all new versions are handled the same way. The fix for a serious vulnerability is installed as soon as it is published: waiting leaves the door open. Other new versions can wait a few days, because a freshly published version is where malicious code slips in. In 2018, an attacker took over maintenance of the event-stream package and added code to it that targeted the bitcoin wallets of the Copay application (npm). In September 2025, the account of the maintainer of chalk, debug and some twenty other JavaScript packages was hijacked through a fake password reset email; according to StepSecurity, a cybersecurity company, these packages were then downloaded billions of times a week (StepSecurity). A few days later, the Shai-Hulud worm, which spread on its own from one package to the next, had compromised more than 500 of them; CISA then recommended pinning dependencies to known safe versions released before 16 September 2025 (CISA).
That gives six practices.
Pin the exact version in the file that declares the dependencies. The application then gets a new version when someone decides it, not when it is published. With a lock file committed with the code (next practice), a version range only comes into play at update time. It is therefore not a vulnerability in itself: the exact version is a team rule, which makes every update deliberate. For a PHP application, composer.lock is enough to rebuild exactly what is in production; exact versions in composer.json remain optional. To date, our own site’s pipeline rejects any dependency declared without its exact version.
Keep the lock file with the code. This file records the exact version of every component installed, including the components your components depend on, and the Composer documentation asks for it to be committed with the project’s code (Composer).
Install from this file, and only update by decision. The pipeline installs exactly the versions in the lock file. An update is decided component by component, and tested.
Wait before adopting a freshly published version. The pnpm package manager offers this delay, currently set by default to one day since its version 11, to reduce the risk of installing compromised or defective packages. Its documentation states that malicious releases are usually discovered and removed from the registry within an hour (pnpm). The fix for a serious vulnerability does not follow this delay: it is installed as soon as it is published, once you have checked that it is indeed announced by the vendor.
Block install scripts, except those you have allowed. A JavaScript package can run any command at the moment it is installed, and OWASP advises turning these scripts off. Currently, pnpm blocks them by default, except for the packages the team has allowed one by one (pnpm). Composer, for PHP, only runs the scripts of the project itself, and loads no plugin that its allow-plugins list does not name (Composer): all it takes is not to loosen that setting.
Pin the language version too, and check that every environment uses it. The runtime, PHP or Node.js, is treated as a dependency. Jez Humble and Dave Farley ask for testing on environments as similar as possible to production, with the same software installed. We therefore advise having the project declare the language version that production uses, and having the pipeline fail if an environment uses another one. That version must be kept up to date as well: NIST, the US National Institute of Standards and Technology, asks organisations, in its Secure Software Development Framework (SSDF), to use up-to-date versions of compilers, interpreters and build tools.
The opposite risk exists too: pinning your versions and never updating them again. Based on our own calculations from W3Techs data, in October 2026 nearly half of PHP sites were running a version the PHP team no longer patches. A pinned version only protects you if updates keep coming: often, one at a time, and tested. Jez Humble and Dave Farley make it a general principle: “If It Hurts, Do It More Frequently, and Bring the Pain Forward.” An update made every week changes little at a time; an update put off for two years becomes a project.
New vulnerabilities are published every day in code that has not changed. A check run only when a change is made misses the vulnerabilities published in the meantime. Composer, the tool that manages the components of a PHP application, can compare the installed components with the security advisories published on Packagist, the main repository of PHP components, and also reports abandoned components (Composer). Run every day by a scheduled pipeline job, this check reports a vulnerability as soon as its security advisory is published. In Continuous Delivery Pipelines, Dave Farley asks for security to be tested in the pipeline, from the very first stage, and not treated as a separate check.
Once a week, another check lists the components for which a new version exists. This reminder prevents the two-year gap.
A scheduled check can also stop running without anyone noticing, and its silence then looks like good news. We therefore advise adding a heartbeat to every scheduled check: an alert goes out when the expected check has not taken place. No security reference prescribes it; it rests on the alert that Jez Humble and Dave Farley ask for in Continuous Delivery, the one that signals that “a required event has not occurred”.
An alert does not always call for the same response. Two pieces of information decide how urgent it is. Exploitation first: a vulnerability that is already exploited comes before a more serious one that is not yet. CISA keeps the list of exploited vulnerabilities: it sets deadlines for US federal agencies to fix them, and recommends that every organisation address them “immediately”. FIRST, the international organisation that publishes the CVSS severity scale, also releases EPSS every day, an estimate of the probability that a vulnerability will be exploited within thirty days.
Severity next: most security advisories give a CVSS score, from 0 to 10, which FIRST groups into five levels: none (0), low (0.1 to 3.9), medium (4 to 6.9), high (7 to 8.9) and critical (9 to 10) (CVSS 4.0). The PHP2Shell vulnerabilities are scored 9.2: critical. This score compares the severity of one vulnerability with others; it does not measure the risk to your business.
In practice, we advise fixing, on the day the fix is published, any vulnerability that is already exploited or critical: in doing so we extend CISA’s recommendation, which covers exploited vulnerabilities. The others follow the normal pace of updates, one at a time.
Some alerts are not dealt with straight away: the affected part of the component is never called by the application, or no fix exists yet. NIST asks for the reason for each such exception to be recorded, and for all approved exceptions to be re-evaluated periodically. We add an expiry date to each one, on which the pipeline fails and the exception has to be decided afresh: no reference prescribes it; it is our way of enforcing the re-evaluation NIST asks for.
These tools have a limit, and PHP2Shell shows it. They examine the libraries the application declares, not the language that runs it. A component check with no alert says nothing about PHP2Shell. The PHP version is monitored separately: the PHP team publishes the list of supported versions and a news feed of its releases. The NCSC asks for software supported by the vendor, and for plans to migrate as the end of support approaches: PHP 8.2 receives none after 31 December 2026.
A composer.json with exact versions (component names given as examples):
{
"require": {
"vendor/component-a": "2.3.1",
"vendor/component-b": "5.0.4"
}
}
Instead of "^2.3.1", which would accept any version from 2.3.1 up to, but not including, 3.0.0 (Composer). Currently, npm writes ^ by default: ^1.2.3 accepts any version from 1.2.3 and below 2.0.0 (node-semver). For npm, save-exact=true in .npmrc makes it write the exact version by default (npm).
An example GitLab pipeline, given as an illustration to adapt: a check on every push, a daily job and a weekly job, each triggered by its own GitLab schedule (schedules, rules).
# Illustrative example, to adapt to your project
stages: [commit, audit]
.php:
# Your project's image with PHP and Composer, pinned by its digest
image: registry.example/php-composer@sha256:<digest>
commit:
extends: .php
stage: commit
script:
# Checks that composer.json and composer.lock are consistent
- composer validate --strict
# Fails if a component, production or development, has a security advisory
- composer audit --locked
# Installs exactly the versions in the lock file
- composer install --no-interaction --prefer-dist
rules:
- if: $CI_PIPELINE_SOURCE == "push"
daily-audit:
extends: .php
stage: audit
script:
# Same check every day, with no code change; also fails on abandoned components
- composer audit --locked --abandoned=fail
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_KIND == "daily"
weekly-reminder:
extends: .php
stage: audit
script:
# Lists the new versions available, without failing the pipeline: this is the reminder
- composer outdated --direct
rules:
- if: $CI_PIPELINE_SOURCE == "schedule" && $SCHEDULE_KIND == "weekly"
composer.lock, or package-lock.json for npm) is committed with the code. The pipeline runs composer install, which installs exactly the versions in this file; composer update recalculates the versions and rewrites the file: it is only for a decided update, for example composer update vendor/component-a (Composer).minimumReleaseAge for pnpm, min-release-age for npm (setting names as of October 2026). For Composer, we advise enforcing this delay through a team rule, or through the tool that proposes updates.composer audit returns a non-zero exit code when a component is covered by an advisory: the job turns red, and that is the alert. --locked reads the lock file, even without a vendor folder (Composer): the example therefore runs the check before composer install, and the job stops before installing a component covered by an advisory. The example also checks development components: they run in the pipeline, which has access to the code and to the deployment secrets.php image, hence the project image in the example.@sha256:…): the Docker documentation states that this guarantees “that the image you’re using is always the same”, and warns that Docker then does not pull updated versions of the image, “which may include security updates” (Docker). Pinning therefore only makes sense with a regular update of the digest, tested by the pipeline.integrity field), and installation fails if the downloaded package does not match. For a script or a stylesheet loaded from another domain, the integrity attribute (Subresource Integrity) makes the browser refuse a modified file (MDN). OWASP asks you to enable checksum verification and signature verification for downloaded packages. Renovate or Dependabot can propose these updates as merge requests; they deploy nothing themselves (Renovate, Dependabot).https://www.php.net/feed.atom). Google’s OSV-Scanner currently reads composer.lock and, in a container image, Alpine and Debian or Ubuntu packages: it can spot a PHP installed by the image’s operating system.allowBuilds lists the packages allowed to run a script at install time (pnpm); for npm, ignore-scripts=true in .npmrc (OWASP). For Composer, allow-plugins names only the plugins needed, never true for all of them (Composer).require.php in composer.json, and composer check-platform-reqs, which fails when the environment’s PHP version or one of its extensions does not match; config.platform makes Composer choose dependencies for the PHP version used in production (Composer). For Node.js, the engines field of package.json, with engine-strict=true, makes installation fail on another version.audit.ignore, in composer.json, records the reason for each ignored advisory (Composer).For software you install and use off the shelf (Windows, macOS, a phone, a browser, office software), we advise switching on automatic updates, as the NCSC asks. On a WordPress site, we advise against the automatic updates WordPress applies on its own.
An application that you develop, or assemble from components, is updated only when someone decides to. The NCSC’s Cyber Essentials scheme leaves the bespoke components of web applications out of its scope, and recommends “robust development and testing” for them. OWASP, in its 2025 ranking of the most critical risks to web applications, asks you to “deliberately choose which version of a dependency you use and upgrade only when there is need”, and to “avoid deploying updates to all systems simultaneously”. Its ranking of the risks specific to CI/CD pipelines asks you not to configure tools to always fetch the latest version of a package. We recommend that every update, whether of the language or of a component, goes through the deployment pipeline and its automated tests.
This approach assumes someone takes care of maintenance. The alerts are what gets automated: an alert when a vulnerability affects the versions in place, an alert when something abnormal happens on the server, which warns you the moment it happens. It is up to a person to decide when to update, and to apply the fix for a critical or already exploited vulnerability without waiting.
For a WordPress site or a PHP application, it depends on the hosting whether the host updates PHP or you do. On WordPress, plugins and themes are updated one at a time.
Every change to the code can also introduce a vulnerability: the pipeline therefore checks the code the team writes, as it checks the dependencies. Dave Farley, quoted above, also asks for common penetration tests to be automated. NIST recommends a static analysis tool that checks the code automatically, and dynamic vulnerability testing built into the automated tests.
Static analysis reads the code without running it, and finds code patterns known to cause vulnerabilities. Semgrep, one of several open-source tools, has rules for PHP as well as for JavaScript. These tools also flag cases that are not problems: someone has to review every alert, and NIST asks for the issues found to be recorded and triaged.
Dynamic testing queries the running application, as a visitor would. The baseline scan of ZAP, an open-source web application security testing tool, does not perform any actual attack: it observes the site’s responses, and reports for example a missing security header. Its documentation describes it as suited to a pipeline, and even to a production site. An active scan, which sends real attacks, is only run on a test environment, never on production.
Fuzzing feeds the program unexpected or random data, to see whether it handles it badly. NIST lists it among its examples. In our view, it is not needed for an ordinary web application; it is justified for code that reads and interprets data received from outside, such as a file format.
Check that no secret gets into the code. We advise a secret-detection tool, such as gitleaks, that examines every change before it is committed and pushed; the pipeline then scans the whole history of the code, in case that first check was bypassed. OWASP recommends detecting secrets before a change is even committed, and using more than one tool to do so. A secret committed by mistake is revoked and replaced: OWASP asks for an exposed key to be revoked immediately.
Everything above rests on one capability: putting a fix into production on the same day, without breaking anything. This capability cannot be improvised on the day of the alert. It depends on how the software is delivered day to day.
In our experience, in an organisation where every release to production is a rare operation (one evening a quarter, tests done by hand, several people mobilised), a critical vulnerability arrives as an emergency. You have to put together an urgent fix outside the schedule, gather the people who know how to deploy, redo the tests by hand, book a maintenance window, sometimes get a committee’s approval. The fix becomes a project, and in the meantime the application stays exposed. This delivery pace pushes people to fix things directly on the server, by hand. In Continuous Delivery, Jez Humble and Dave Farley reject this shortcut outright: when a critical defect is found, “Do not, under any circumstances, subvert your process.” They also point out that it is sometimes better to roll back to the previous version than to deploy a fix. A fix made by hand in production is untested, can make the problem worse, and is often recorded nowhere.
The problem goes beyond any one framework. It affects every predictive approach, the V-model as much as frameworks presented as agile, as soon as a feature is committed to with its scope, budget and deadline all fixed at once, then slotted into a schedule built on estimates. SAFe (Scaled Agile Framework), for example, plans work in intervals of eight to twelve weeks, each with its own objectives and delivery dates. These organisations do plan for emergency fixes, which take priority over everything else. Yet each one remains an exception to the schedule: it takes a less well-practised path than planned releases, and pushes back what had been committed to. In Accelerate, Nicole Forsgren, Jez Humble and Gene Kim write: “Short lead times are also important when there is a defect or outage and we need to deliver a fix rapidly and with high confidence.”
Yet unplanned work is taking up more and more room: more vulnerabilities published, so more fixes that cannot wait. AI does not create these organisations’ weaknesses: it exploits them faster. As Amazon puts it, “A 7-day or 30-day SLA assumes a delay that no longer exists.” The NCSC asks organisations to make sure their “processes and risk appetites support frequent and scaled-updating”.
In our view, this predictive way of working exposes above all the organisations that keep to it: every urgent fix upsets a schedule that had made no room for it, and in the meantime the system stays exposed. In an adaptive approach, scope evolves with priorities, and with Continuous Delivery the fix goes ahead of everything else and follows the same path as every other change, on the same day. In their survey, the authors of Accelerate found that the highest-performing organisations in software delivery were twice as likely as the others to report exceeding their profitability and market share goals.
Applying a fix does not mean handing the system over to cybersecurity experts. It is the everyday work of the team that develops the application: it updates the component concerned, the deployment pipeline checks the change with the automated tests, then puts it into production. DORA calls on teams to “Integrate InfoSec into the daily work of the entire software delivery lifecycle”, because “Security is everyone’s responsibility”.
With Continuous Delivery, practised as part of an adaptive approach, that is, adjusting the software continuously based on how it is used, the same fix is a change like any other. Jez Humble defines Continuous Delivery as “the ability to get changes of all types, including new features, configuration changes, bug fixes and experiments, into production, or into the hands of users, safely and quickly in a sustainable way” (continuousdelivery.com). Dave Farley specifies that the deployment pipeline is “the ONLY route to production”: every change goes through it, the PHP update as much as the new feature. It goes through the same automated tests, then to production. Because every change follows this path, the procedure is already well practised on the day a fix arrives.
This discipline also changes how the project is managed. A critical vulnerability is not scheduled for the end of the week: it jumps ahead of everything else, the same day. A team that keeps to the discipline of Continuous Delivery can change its priorities within the day, according to what comes up, because nothing in progress blocks the release of the fix.
So that nothing in progress holds the fix back, Jez Humble and Dave Farley advocate that everybody checks in on mainline, and that you “hide new functionality until it is finished”: this is trunk-based development, where everyone integrates their work into a single branch, several times a day. An urgent fix then follows the same path as everything else, without waiting for a feature to be finished. To hide an unfinished feature, a configuration setting is enough; the same authors ask for these settings to be removed once they have served their purpose. It is a Continuous Delivery practice, which security frameworks do not address.
We advise having the pipeline build the application only once, then deploy the same archive to every environment. “Every time you compile the code, you run the risk of introducing some difference”, write Jez Humble and Dave Farley. The rule applies to PHP too, which is not compiled. The archive contains the code, the components installed by Composer and the static files; it is the archive that goes to production, and nothing is installed directly on the server. After every deployment, a smoke test, a quick test, checks that the application responds. Rolling back then means redeploying the previous archive, which the same authors describe as often the simplest way to roll back. Data limits this: a database changed by the new version does not return to its previous state by itself.
DORA (DevOps Research and Assessment), Google Cloud’s research programme on how software is developed and released, measures what this practice changes. DORA does not directly measure how long it takes to apply a fix. The closest metric is the lead time for a change, from the moment it is committed to the code to the moment it is in production. In Modern Software Engineering, Dave Farley asks a related question: how long does it take for a single-line change to go from “idea” to “working software”? In our view, that time is also how long it will take to apply the next security fix. DORA’s research has repeatedly shown that “speed and stability are not tradeoffs” (DORA). According to a summary of the 2024 report published by Octopus Deploy, a vendor of deployment tools, the highest-performing teams get a change into production in less than a day, and recover from a failed deployment in less than an hour (Octopus Deploy, DORA 2024 report).
Change approval boards do not make up for slow delivery. In Modern Software Engineering, Dave Farley quotes the research published in the book Accelerate: “approval by an external body (such as a manager or CAB) simply doesn’t work to increase the stability of production systems […] It is, in fact, worse than having no change approval process at all.”
Security guidance sets a different timeframe. The NCSC’s Cyber Essentials requirements ask for updates that fix vulnerabilities rated critical or high risk to be applied within 14 days of release, and strongly recommend applying all released updates within 14 days. OWASP, in its 2025 ranking of the ten most critical risks to web applications, warns against this pace: exposure “commonly happens in environments when patching is a monthly or quarterly task under change control, leaving organizations open to days or months of unnecessary exposure before fixing vulnerabilities”. The 14-day timeframe is presented as a maximum, and the time to exploit has fallen to a few days. With attacks that sometimes start before the fix is published, it is no longer enough as a goal. Checking a patch does not require waiting two weeks: automated tests in the pipeline carry it out on every change.
Jamie Dimon, chairman and chief executive of JPMorgan Chase, pointed in October 2026 to two risks: AI agents acting on their users’ bank accounts, and AI tools uncovering hundreds of serious vulnerabilities in open source code, leaving “industries completely unprotected”. At the time of writing, his bank gives outside AI agents read-only access to its retail customers’ accounts.
For the vulnerabilities AI uncovers sooner, Continuous Delivery addresses how long it takes to apply the fix. As early as 2010, in Continuous Delivery, Jez Humble and Dave Farley called for the ability to release a new version quickly “in case critical defects or security holes are found”. They also asked for production to be “completely locked down”, so that only the deployment pipeline can make changes to it. With these practices and those described in the section on the delivery approach, the fix for a vulnerability found by AI goes to production like any other change. In our view, Continuous Delivery shortens the time during which a vulnerability whose fix exists remains exploitable in your systems; finding vulnerabilities and stopping attacks are the job of the other practices described in this article.
The other risk Jamie Dimon describes is a matter of access rights: knowing whether an agent really acts for the person who authorised it, for a bank as for any application. OWASP lists “Excessive Agency” among the risks of AI applications, and the NCSC asks for the principle of least privilege to be applied to agents. If your application lets AI agents act for your users, we advise, as OWASP does, giving them only the minimum rights they need, making them act in the context of the user concerned, and having a person approve high-impact actions.
On the day a vulnerability hits your software, the course of action comes down to eight steps. It draws on the NCSC’s 10 Steps to Cyber Security guidance, in particular its pages on incident management, data security and logging and monitoring, and on the Information Commissioner’s Office guidance on reporting a personal data breach. Read them before that day comes, and agree on who does what.
The first three steps depend on the vulnerability. For PHP2Shell, that means finding out whether you are exposed, updating or isolating, then looking for signs of intrusion. The next five apply to any vulnerability.
4. Preserve evidence before cleaning up. We advise collecting the logs of the firewall, the reverse proxy and the affected servers, and making a full copy of the attacked machine and its memory. Redeploying a clean version before taking this copy wipes out exactly the evidence you need to understand what happened.
5. Change every secret the server held. We advise changing the database passwords, the application keys (WordPress keys and salts, Laravel’s APP_KEY, Magento’s encryption key), the access keys to third-party services (payment, email sending, storage), the messaging accounts, the deployment tokens present on the server, the private keys of certificates and the administrator accounts, and closing open sessions. The new secrets are generated from a clean environment and deployed only to the server rebuilt in the next step, never to the server that is still compromised. CosmicSting showed it: a key stolen before the fix remains valid after it, and Sansec recommends replacing the encryption key and invalidating the old one. Changing the application key logs all users out; that is expected. Data encrypted with the old key is another matter: it becomes unreadable unless the old key stays available to decrypt it or the data is re-encrypted with the new one. Laravel lets you keep previous keys for decryption (APP_PREVIOUS_KEYS), and, for Magento, Adobe provides a key rotation procedure and a command that re-encrypts the data.
6. If the server was compromised, rebuild from a clean source. We advise against restoring the old server image or the old code, which may contain the web shell. With a pipeline, you rebuild the server and the application from the code repository, at a clean version, with the fix. In our view, data should be restored from a backup taken before the earliest possible date of intrusion. This is where offline, tested backups make the difference. We advise a gradual return to service, after making sure the vulnerability is fixed.
7. Report. If personal data may have been accessed, altered or destroyed, the incident must be notified to the Information Commissioner’s Office, the UK data protection authority, within 72 hours, the deadline the UK GDPR sets. Also notify your insurer of the incident. For support, we advise calling on a qualified security incident response provider. In an emergency, call 999.
8. Learn the lessons. Ask what we have learned: the NCSC asks you to update your response plans after every incident. How long did it take to apply the fix, and why? DORA measures the closest indicator to this delay, described above: the shorter it is day to day, the sooner after its publication the next fix will be applied. What made it possible, or would have made it possible, to notice the attack?
A security fix is a change like any other: it goes through the same pipeline as everything else. We do not look for vulnerabilities; that research belongs to researchers. Our role is to limit what the next vulnerability will let an attacker reach, to be alerted as soon as it is exploited, and to apply its fix as soon as it is published.
The same team develops, tests, deploys and maintains your software continuously, in the same pipeline. Every production deployment goes through a deployment pipeline: security and accessibility are verified automatically before reaching production, and performance is monitored in production. We put one change at a time into production, after it has been checked by the pipeline. If there is an incident, we roll back to the previous version.
For the applications we develop, here is what we set up with a deployment pipeline. Every dependency is pinned to its exact version. A freshly published version is only adopted once it has been out for three days, except the fix for a serious vulnerability: we then lift that delay, case by case, to install it as soon as it is published. Every morning, a scheduled job checks whether a known vulnerability affects the components in place. We also set up monitoring of the servers, with alerts on the signals described above. An update of PHP or of a component goes through the same pipeline as everything else.
Security fixes and dependency updates are part of the maintenance included in our offer: custom software on a fixed monthly budget, with a zero-regression guarantee.
We also offer software production chain audits and training for technical teams. The audit checks whether a flaw found in your software can be fixed and delivered to your customers the same day, and what remains to be put in place.
A security update reaches production on the day it is published when every change already gets there in small steps. Our article on Continuous Delivery and Continuous Deployment explains how this works, and our article on the predictive or adaptive approach why this way of delivering belongs to an adaptive approach.
To take over an application whose language or components are no longer maintained, our application takeover and redesign page explains how we go about it.
Do you have an application to have built, or to take over? Shall we talk?
save-prefix, save-exact, min-release-age).allow-plugins, platform, audit) and “Scripts”.
What is shadow IT? The definition from the UK's National Cyber Security Centre, examples (Excel, AI tools), the risks for the business, and why the answer is a tool that fits the work.
Should you enable or disable WordPress automatic updates? We advise against the ones WordPress applies on its own to plugins and themes, without any testing. A host that tests each update before applying it can handle them; without one, update one plugin at a time, then check the site.
On 21 October 2026, PHP fixed two critical vulnerabilities, on the same day as GitLab and Node.js. Who is affected, what to do that same day, and how to limit the damage a vulnerability can do.