diff --git a/src/content/articles/node-security/index.mdx b/src/content/articles/node-security/index.mdx index 1a165aa..3fbdb97 100644 --- a/src/content/articles/node-security/index.mdx +++ b/src/content/articles/node-security/index.mdx @@ -83,6 +83,7 @@ Goal: shrink the blast radius across the four targets (developer, CI/CD, servers - Commit your lockfile. Always install with a lockfile-enforcing mode: - `npm`: `npm ci` - `pnpm`: `pnpm install --frozen-lockfile` + - `yarn` (Classic): `pnpm install --frozen-lockfile` - `yarn` (Berry): `yarn install --immutable` - Enable Corepack and declare the package manager/version in `package.json` to prevent lockfile confusion and mismatched security settings across machines and CI. - Run `corepack enable` @@ -93,9 +94,9 @@ Goal: shrink the blast radius across the four targets (developer, CI/CD, servers - **What to do:** - **Default to no install scripts, then allow only what’s required:** - - **`pnpm`:** Use `onlyBuiltDependencies` in `.npmrc` to whitelist packages that may run install scripts (great for native modules). You can also set `ignore-scripts=true` when you know nothing should run. + - **`pnpm`:** Use [`onlyBuiltDependencies`](https://pnpm.io/settings#onlybuiltdependencies) in `pnpm-workspace.yaml`/.npmrc` to whitelist packages that may run install scripts (great for native modules). You can also set [`strictDepBuilds`](https://pnpm.io/settings#strictdepbuilds) which makes the build fail if it has unreviewed install scripts. - **`npm`/`yarn`:** Disable scripts by default (`npm config set ignore-scripts true` or `yarn config set enableScripts false`), then run needed scripts explicitly for approved packages (e.g., `npm rebuild `). - - For npm/yarn whitelisting at scale, use a maintained helper like LavaMoat’s `allow-scripts` (`npx @lavamoat/allow-scripts`) to manage an explicit allow-list. + - For npm/yarn whitelisting at scale, use a maintained helper like [LavaMoat’s `allow-scripts`](https://www.npmjs.com/package/@lavamoat/allow-scripts) (`npx @lavamoat/allow-scripts`) to manage an explicit allow-list. - Treat `prepare` scripts as “runs on dev boxes and CI” code—only allow for packages you trust to execute on your machines. - **Why it helps:** Install hooks are a primary path to dev and CI credential theft. A deny-by-default stance turns “one malicious `preinstall`” into “no-op unless allowlisted.” @@ -103,9 +104,9 @@ Goal: shrink the blast radius across the four targets (developer, CI/CD, servers - **What to do:** - **Delay non-security updates** to let the ecosystem notice regressions or malicious releases: - - **`pnpm`:** Set `minimumReleaseAge` in `pnpm-workspace.yaml` or `.npmrc` (e.g., `10080` for 7 days). - - **Renovate:** Use `stabilityDays` to hold PRs until a package has “aged.” - - If you prefer manual updates, tools like `taze` can help you batch and filter upgrades. + - **`pnpm`:** Set [`minimumReleaseAge`](https://pnpm.io/settings#minimumreleaseage) in `pnpm-workspace.yaml` or `.npmrc` (e.g., `10080` for 7 days). + - **Renovate:** Use [`minimumReleaseAge`](https://docs.renovatebot.com/configuration-options/#minimumreleaseage) to hold PRs until a package has “aged.” + - If you prefer manual updates, tools like [`taze`](https://www.npmjs.com/package/taze) can help you batch and filter upgrades. - **Exception:** apply security patches immediately (Dependabot/Renovate security PRs). - **Why it helps:** Many supply-chain incidents are discovered within a few days. A short delay catches a lot of fallout without leaving you perpetually stale. @@ -113,7 +114,7 @@ Goal: shrink the blast radius across the four targets (developer, CI/CD, servers - **What to do:** - Enable GitHub Dependabot alerts and (optionally) security updates. - - Consider a second source like Snyk, Trivy or Socket.dev for malicious-pattern detection beyond CVEs. + - Consider a second source like [Snyk](https://snyk.io/), [Trivy](https://trivy.dev/latest/) or [Socket.dev](https://socket.dev/) for malicious-pattern detection beyond CVEs. - Make `audit` part of CI (`npm audit`, `pnpm audit`, `yarn dlx npm-check-updates + advisories`) but treat results as signals, not gospel. - **Why it helps:** Quick detection matters; you can roll back or block promotion if an alert fires. @@ -121,17 +122,17 @@ Goal: shrink the blast radius across the four targets (developer, CI/CD, servers - **What to do:** - **Prefer runtime secret injection over files on disk.** Examples: - - 1Password: `op run -- ` (https://developer.1password.com/docs/cli/reference/commands/run/) - - with-ssm: `with-ssm -- ` (https://github.com/morten-olsen/with-ssm, disclaimer; made by me) + - [1Password: `op run -- `](https://developer.1password.com/docs/cli/reference/commands/run/) + - [with-ssm: `with-ssm -- `](https://github.com/morten-olsen/with-ssm, disclaimer; made by me) - Separate secrets available at install vs runtime. Most builds don’t need prod creds—don’t make them available. - - In CI, use OIDC federation to clouds (e.g., GitHub Actions → AWS/GCP/Azure) for short-lived tokens instead of static long-lived keys. + - [In CI, use OIDC federation to clouds (e.g., GitHub Actions → AWS/GCP/Azure) for short-lived tokens instead of static long-lived keys. ([AWS](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-aws)) - Never expose prod secrets to PRs from forks. Use GitHub environments with required reviewers and “secrets only on protected branches.” - **Why it helps:** Even if an attacker runs code, they only get ephemeral, least-privilege creds for that one task—not the keys to the kingdom. ### 6. SSH Keys: Hardware-Backed or at Least in a Secure Agent - **What to do:** - - Prefer a hardware token (YubiKey) for SSH and code signing. + - [Prefer a hardware token (YubiKey) for SSH and code signing.](https://github.com/drduh/YubiKey-Guide) - Or use a secure agent: [1Password SSH Agent](https://developer.1password.com/docs/ssh/agent/) or [KeePassXC’s SSH agent support](https://keepassxc.org/docs/#faq-ssh-agent-keys). - Limit key usage to specific hosts, require touch/approval, and avoid storing private keys unencrypted on disk. - **Why it helps:** Reduces credential theft on dev boxes and narrows lateral movement if a machine is compromised. diff --git a/src/layouts/article/article.astro b/src/layouts/article/article.astro index bd6bc06..0fc24d9 100644 --- a/src/layouts/article/article.astro +++ b/src/layouts/article/article.astro @@ -196,6 +196,10 @@ console.log('foo', Content) :global(code) { font-family: monospace; } + + :global(a) { + text-decoration: underline; + } } @media (max-width: 1024px) {