Cyber Essentials for Development Teams
Cyber Essentials is the UK Government's baseline security scheme. It defines five technical controls that protect against the most common internet-based attacks. Most guidance is written for IT administrators - this guide translates each control into concrete actions for development teams shipping software.
If your organisation is in a UK Government supply chain, or sells to enterprises that require Cyber Essentials certification, these controls are not optional. As mandating Cyber Essentials in procurement frameworks expands, understanding what they mean for your codebase and pipelines matters now.
Reference: NCSC - Cyber Essentials Reference: Cyber Essentials Requirements (PDF)
The five controls
| Control | IT framing | Developer framing |
|---|---|---|
| Firewalls | Boundary firewalls and internet gateways | Network segmentation, ingress rules, WAF/CDN config |
| Secure configuration | Remove unnecessary software, change defaults | Harden container images, remove debug endpoints, rotate default credentials |
| User access control | Least privilege, individual accounts | RBAC/ABAC in application code, service account scoping, MFA |
| Malware protection | Anti-malware software | Dependency scanning, container scanning, CI security gates |
| Security update management | Patch within 14 days for critical | Automated dependency updates, patch SLAs, image rebuild pipelines |
Control 1: Firewalls - boundary protection
For development teams this means:
- Production services are not directly exposed to the internet without a reverse proxy, CDN, or load balancer
- Only necessary ports are open - no SSH, database, or admin ports are publicly accessible
- Infrastructure-as-code templates explicitly define security groups and ingress rules
- Development and staging environments are not publicly accessible (use VPN or IP allowlisting)
- Cloud provider firewalls (AWS Security Groups, GCP Firewall Rules, Azure NSGs) are reviewed in code review
# Terraform - explicit ingress, deny by default
resource "aws_security_group" "web" {
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# No other ingress - SSH via SSM, not port 22
}
Common failure: Leaving database ports (3306, 5432, 27017) open in development security groups that get promoted to production.
Control 2: Secure configuration
For development teams this means:
- Default admin credentials are changed or removed before deployment
- Debug modes, verbose error pages, and development endpoints are disabled in production
-
.envfiles,docker-compose.override.yml, and development configs are not deployed - Container images use minimal base images (distroless, Alpine) with no unnecessary packages
- Server headers that leak technology versions are suppressed (
X-Powered-By,Server) - Auto-generated admin routes (e.g.
/admin,/graphql/playground) are gated or removed
# Minimal production image - no shell, no package manager
FROM gcr.io/distroless/nodejs22-debian12
COPY --from=build /app/dist /app
CMD ["server.js"]
Common failure: Shipping a Next.js or Rails app with development error pages that leak stack traces and file paths.
Control 3: User access control
For development teams this means:
- Application authentication enforces MFA where supported (or delegates to an IdP that does)
- Authorisation checks happen server-side on every request, not just in the UI
- Service accounts use scoped credentials with the minimum permissions needed
- CI/CD runners use short-lived, scoped tokens - not long-lived personal access tokens
- Admin access to production systems is logged and uses separate credentials from day-to-day accounts
- Default accounts and API keys shipped by frameworks or dependencies are removed
// Server-side authorisation check - not just a frontend guard
export async function updateProject(projectId: string, data: UpdateData) {
const user = await getAuthenticatedUser();
const project = await db.project.findUnique({ where: { id: projectId } });
if (project.ownerId !== user.id && !user.roles.includes("admin")) {
throw new ForbiddenError("Not authorised to update this project");
}
return db.project.update({ where: { id: projectId }, data });
}
Common failure: CI pipelines using a single shared token with write access to every repository and deployment target.
Control 4: Malware protection
Traditional malware protection means antivirus. For development teams, the equivalent is automated scanning for known-bad code in your dependencies and containers:
- Software Composition Analysis (SCA) runs in CI on every pull request
- Container images are scanned for known vulnerabilities before deployment
- A clear exceptions/waiver process exists for dependencies with known CVEs that cannot be immediately updated
- Lock files (
package-lock.json,pnpm-lock.yaml,poetry.lock) are committed and reviewed - Dependency sources are pinned to trusted registries - no unvetted third-party mirrors
# GitHub Actions - SCA on every PR
- name: Audit dependencies
run: npm audit --audit-level=high
- name: Scan container image
uses: aquasecurity/trivy-action@master
with:
image-ref: ${{ env.IMAGE }}
severity: CRITICAL,HIGH
exit-code: 1
Common failure: SCA is enabled but generates so many alerts that the team ignores them. Set a severity threshold and maintain a reviewed exceptions list.
Control 5: Security update management
Cyber Essentials requires critical patches to be applied within 14 days. For development teams:
- Automated dependency update tools (Dependabot, Renovate) are enabled and PRs are reviewed promptly
- Container base images are rebuilt regularly - at least weekly - to pick up OS-level patches
- An emergency deployment path exists to push critical security fixes to production within days, not weeks
- End-of-life runtimes and frameworks are tracked and upgraded before support expires
- The team has a documented SLA: critical CVEs patched within 14 days, high within 30 days
# Renovate - auto-merge patch updates, flag breaking changes
{
"extends": ["config:recommended"],
"packageRules": [
{
"matchUpdateTypes": ["patch"],
"automerge": true
}
]
}
Common failure: Base images pinned to a specific tag that was last updated 18 months ago.
Mapping to your CI/CD pipeline
A practical way to verify Cyber Essentials alignment is to check your pipeline:
| Pipeline stage | CE control | Automated check |
|---|---|---|
| PR opened | Malware protection | SCA scan, container scan |
| PR opened | Secure configuration | Lint for debug flags, default credentials |
| Pre-merge | User access control | CODEOWNERS review, scoped deploy tokens |
| Build | Secure configuration | Minimal base image, no dev dependencies |
| Deploy | Firewalls | IaC security group validation |
| Scheduled | Security updates | Dependency update PRs, image rebuild |
Cyber Essentials Plus
Cyber Essentials Plus adds a hands-on technical audit on top of the self-assessment. For development teams, this means an assessor will verify that:
- Patching is actually happening (not just configured)
- Access controls are enforced in practice
- Scanning tools are generating actionable results
If you are preparing for Plus, ensure your CI dashboards can demonstrate compliance history - green builds, resolved dependency alerts, and patch deployment dates.
Further reading
Content is AI-assisted and reviewed by our team, but issues may be missed and best practices evolve rapidly, send corrections to [email protected]. Always consult official documentation and validate key implementation decisions before making design or security choices.
