

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Still calibrating
click for more info
Not enough gems
Cost: 6 gems
1: Managing Secrets
incomplete
2: Injecting Secrets at Runtime
incomplete
3: Protecting Secrets
incomplete
4: Build Artifacts and Deployment Hygiene
incomplete
5: Limiting Build Context
incomplete
6: Source Code and Config Leaks
incomplete
7: Public File Leaks
incomplete
8: Server-Side Request Forgery
incomplete
9: Defending Against SSRF
incomplete
10: Open Redirects
incomplete
11: Risks of Dependencies
incomplete
12: Auditing Dependencies
incomplete
13: Dependency Maintenance
incomplete
Back
ctrl+,
Next
ctrl+.
This lesson's interactive features are locked, please to keep using them
A production container (like a Docker container) should have access to what the app needs to run and not much else. Extra tools and files increase image size and give an attacker more to work with.
Imagine a media app that runs TypeScript directly using Node.js 24. Its Dockerfile might look like this:
FROM node:24-alpine
WORKDIR /app
COPY . .
RUN npm ci
CMD ["npm", "start"]
It copies the entire build context, installs development tooling in the final image, and runs as the default root user. Not great.
A multi-stage build can prepare production dependencies separately, then copy only the required runtime files into the final stage:
FROM node:24-alpine AS dependencies
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
FROM node:24-alpine AS runtime
WORKDIR /app
COPY --from=dependencies /app/node_modules ./node_modules
COPY package.json ./
COPY src ./src
COPY public ./public
RUN mkdir -p data/uploads data/render-jobs \
&& chown -R node:node data
COPY --chown=node:node data/uploads/sample-poster.webp ./data/uploads/
USER node
CMD ["node", "src/main.ts"]
The exact steps depend on the app, of course. But we shouldn't dump the entire project into production. Explicitly copy only the stuff production needs. The final image is smaller and doesn't include development tools an attacker could use.
Running as a non-root user (node, in this case) limits what a compromised process can do. Of course, the app's user still needs permission to perform its ordinary runtime work.
Bearly Secure's production image currently includes the entire project, development tools, and a root process. Replace it with a narrow, multi-stage Node.js 24 image.
Run and submit the CLI tests from the project root.