Design: Linode (Superseded by Akamai)

Overview

Status: SUPERSEDED by akamai-fetch-processor.

Linode-branded PSIRT publishing was consolidated under Akamai after the acquisition. There is no Linode-scoped advisory feed, blog, or API to fetch — www.linode.com/blog/security/ 301-redirects to www.akamai.com/blog/developers, and there is no separate Linode identifier namespace on Akamai PSIRT.

Linode advisories are ingested through the Akamai pipeline and stored under CVEMetadata.source = "akamai". The Akamai mapper tags any advisory whose title contains linode (case-insensitive) with affectedProduct = "Linode" — see internal/akamai/mapper.go:112-113:

case strings.Contains(t, "linode"):
    return "Linode"
ItemValue
Source slugakamai (NOT linode)
Affected product tagLinode
Binarynone — coverage delivered by akamai-fetch-processor
ECS tasknone
Scheduleinherited from go-akamai-fetch-processor (daily 16:00 UTC)
Anti-bot pathuTLS Chrome 120 ClientHello via internal/httpclient/utls.go

Why no separate binary

  • No first-party feed exists. Every Linode security URL 301s to Akamai.
  • Akamai PSIRT is the canonical surface. The akamai-fetch-processor already crawls every advisory on www.akamai.com/blog/security/ and /blog/security-research/ and grows its seed list via related-link extraction.
  • The TLS-fingerprint gate is solved. httpclient.NewChromeImpersonating in internal/httpclient/utls.go defeats Akamai Bot Manager — the blocker called out in the original 2026-05-08 recon (see Historical Recon below) is no longer load-bearing.
  • A duplicate linode source would double-count. Emitting the same CVE under both source="akamai" and source="linode" would inflate alias graphs and break dedup invariants on CVEMetadata. The product-tag mechanism gives downstream consumers everything a separate source slug would, without the duplication.

The extended dictionary internal/critutil/dictionaries/extended/linode.json (Linode-Compute service entries: compute/instance, objectstorage/bucket, lke/cluster, etc.) remains valid and is consumed by the akamai pipeline whenever a Linode-tagged advisory emits CRIT envelopes.


Inheritance flow

flowchart LR A[Akamai PSIRT page
www.akamai.com/blog/security/...] -->|uTLS Chrome 120
defeats Bot Manager| B[akamai-fetch-processor] B --> C[internal/akamai/parser.go
extract title + CVE + CVSS] C --> D{productFromTitle
title substring?} D -->|contains 'linode'| E[affectedProduct = 'Linode'] D -->|contains 'guardicore'| F[affectedProduct = 'Guardicore'] D -->|else| G[affectedProduct = 'Akamai' or other] E --> H[(CVEMetadata
source='akamai'
affectedProduct='Linode')] F --> H G --> H

Decision flow — “where are the Linode CVEs?”

flowchart TD Q[Customer asks for Linode CVE coverage] --> SQL[Query CVEMetadata
WHERE source='akamai'
AND affectedProduct='Linode'] SQL --> R{Rows returned?} R -->|yes| OK[Hand off — coverage is live] R -->|no, but advisory known| SEED[Add slug to
internal/akamai/seeds.go] SEED --> RUN[Trigger go-akamai-fetch-processor
via task-dashboard or ECS one-off] RUN --> SQL R -->|no advisory exists upstream| ENRICH[Recommend cisa-kev
+ nist-nvd as third-party
enrichment for hypervisor/control-plane CVEs]

Querying Linode coverage

SELECT "cveId", "datePublished", "title", "sourceAdvisoryRef"
FROM "CVEMetadata"
WHERE "source" = 'akamai'
  AND "affectedProduct" = 'Linode'
ORDER BY "datePublished" DESC;

If the result set is empty but a specific Linode advisory is known to exist on Akamai PSIRT, add its slug to scripts/go-processors/internal/akamai/seeds.go and re-run go-akamai-fetch-processor. The crawler will pick it up on the next scheduled run (or via an ECS one-off task) and the same query will return the row.


Historical recon (2026-05-08, retained for audit)

The findings below drove the original DEFERRED verdict. They are preserved because the URLs and protocol observations remain useful for anyone evaluating a similar acquired-vendor scenario in future. The path described above (Akamai PSIRT inheritance via uTLS) is the live solution; the §11 unblock conditions from the original doc have all been satisfied by akamai-fetch-processor.

Recon-protocol grid:

StepCheckFinding
1First-party CSAF 2.0None on linode.com or akamai.com (provider-metadata.json not published).
2First-party CVRFNone.
3First-party RSS / Atom feedlinode.com/blog/security/ 301 → akamai.com/blog/developers; blogs.akamai.com/sitr/feeds.html is a legacy Atom-feed catalogue but the host is gated.
4First-party JSON APINone.
5First-party HTML listingakamai.com/security-research/akamai-security-advisories and individual advisory slugs (/blog/security/advisory-cve-YYYY-NNNN-...) exist and carry CVE-prefixed identifiers, but every URL returned 403 to non-browser fetches in 2026-05-08 testing.
6GitHub Security Advisoriesgithub.com/linode exists; no Security Advisories tab usage.
7CVE alias presenceConfirmed via Google snippets — Akamai PSIRT advisories carry CVE-YYYY-NNNN in URL slug. At the time, could not be fetched without browser-grade TLS fingerprinting.
8Anti-botWas blocking — now solved. akamai.com is fronted by Akamai Bot Manager. Plain Go HTTP client and WebFetch both 403. The uTLS Chrome 120 ClientHello in internal/httpclient/utls.go now defeats this gate.

URLs checked (snapshot 2026-05-08):

  • https://www.linode.com/blog/security/ — 301 → https://www.akamai.com/blog/developers
  • https://www.linode.com/legal/security/ — 200; shared-security-model legal page only
  • https://status.linode.com/ — 200; operational only, no CVEs
  • https://www.akamai.com/global-services/support/vulnerability-reporting — 403 (now reachable via uTLS client)
  • https://www.akamai.com/blog/security — 403 (now reachable via uTLS client)
  • https://www.akamai.com/blog/security/advisory-cve-2025-53841-guardicore-local-privilege-escalation — was 403; now ingested by akamai-fetch-processor as part of seed list
  • https://blogs.akamai.com/sitr/feeds.html — legacy host, status not confirmed

S3 Persistence

Not used. This processor does not currently archive payloads or quarantine failures to S3. Per the S3 Persistence Contract this is non-compliant — see the compliance matrix for the implementation roadmap.

⚠ Not in the compliance matrix — status needs verification.

Expected paths when implemented:

  • Archive: linode/files/{sha256}/{filename}
  • Quarantine: failed-feeds/linode-rss-processor/{YYYY-MM-DD}/{reason}/{filename}
  • Likely reasons: (none documented)