Skip to content
academia.sh

Lesson 02 / 15

Asset, Threat and Vulnerability

Separating three terms into the same inventory: the cartesian product of 8 assets, 6 threats, and 12 vulnerabilities is 576, while the valid-triple count drops to 19, or 3.3%; two assets each carrying two vulnerabilities produce 1 and 4 triples; a vulnerability no threat can reach carries zero triples; two threats carrying the same five triples touch 4 and 5 separate assets; closing five of twelve vulnerabilities closes 12 of the 19 triples; and narrowing an asset's zone closes 3, 2, 1, or no triples at all.

Published Updated

In this lesson

  • Models the asset, threat, and vulnerability terms as separate lists in the same inventory and counts each one
  • Shows step by step, through narrowing, why multiplying the three lists does not give the number of reachable paths
  • Separates vulnerability count from triple count: how many triples closing a given number of vulnerabilities actually closes
Contents

The previous lesson scored eight items and counted which direction six decisions moved those scores. The whole computation ran on a single list, and the names of that list’s parts were left unclear: the thing being protected was called “asset,” but what was the thing that would lower a score, what was the thing that let it drop. This lesson splits the same inventory into three separate lists and counts how the three combine.

Asset is the thing being protected: data, a service, a device, a record. Threat is an agent capable of causing harm; the party capable of doing so is called a threat actor. Vulnerability is the weakness in the asset that lets that harm happen. The three are separate lists and are counted separately. In everyday speech they get used interchangeably; once counted, it becomes clear they are not interchangeable.

Three Lists Answer Three Separate Questions

The example is again the fictional regional measurement network, and the asset list is the same eight items as the previous lesson. The inventory below is a model: there is no real network, no real threat record, no real vulnerability list.

SC6: every asset is named by the widest zone it can be reached from — outer, field, inner. SC7: every vulnerability lives in exactly one asset and carries a type. SC8: every threat is defined by the set of zones it can reach and the vulnerability types it can use. SC9: an (asset, vulnerability, threat) triple is valid only if all three conditions hold together — the vulnerability lives in that asset, the threat reaches that zone, the threat can use that vulnerability type.

// security/inventory.mjs — fictional measurement network's asset, threat, and vulnerability
// inventory (model): there is no real network, threat record, or vulnerability list. No randomness.

// SC6: every asset is named by the widest zone it can be reached from (outer, field, inner).
export const ASSET = `
  reading-data         inner
  billing-record       outer
  work-order-queue     field
  identity-store       inner
  configuration        inner
  audit-log            inner
  meter-firmware       field
  field-app            outer`
  .trim().split("\n").map((r) => { const [name, zone] = r.trim().split(/\s+/); return { name, zone }; });

// SC7: every vulnerability lives in exactly one asset and carries a type.
export const VULN = `
  outdated-library-version    billing-record       version
  default-password             configuration        credential
  broad-read-permission        reading-data          permission
  unvalidated-input            field-app             input
  open-management-endpoint     configuration         configuration
  unsigned-update               meter-firmware        integrity
  shared-account                identity-store        credential
  unencrypted-transfer          work-order-queue      transfer
  unretained-log                audit-log             visibility
  outdated-agent-version        field-app             version
  physical-access-point         meter-firmware         physical
  unvalidated-field             audit-log             input`
  .trim().split("\n").map((r) => {
    const [name, asset, type] = r.trim().split(/\s+/);
    return { name, asset, type, zone: ASSET.find((v) => v.name === asset).zone };
  });

// SC8: every threat is defined by the zones it can reach and the vulnerability types it can use.
export const THREAT = [
  { name: "external-opportunist", zone: ["outer"], type: ["version", "credential", "input", "configuration"] },
  { name: "targeted-external", zone: ["outer", "field"],
    type: ["version", "credential", "input", "configuration", "transfer", "integrity"] },
  { name: "field-proximate", zone: ["field"], type: ["physical", "integrity", "transfer"] },
  { name: "internal-user-error", zone: ["inner", "field"], type: ["configuration", "permission"] },
  { name: "malicious-insider", zone: ["inner", "field", "outer"],
    type: ["permission", "credential", "visibility", "transfer"] },
  { name: "supply-chain", zone: ["field", "inner"], type: ["integrity", "version"] },
];

// SC9: a triple is valid only if the vulnerability reaches that zone and the threat can use
// that vulnerability type.
export const valid = (v, t) => t.zone.includes(v.zone) && t.type.includes(v.type);
export const TRIPLE = VULN.flatMap((v) => THREAT.filter((t) => valid(v, t))
  .map((t) => ({ asset: v.asset, vuln: v.name, threat: t.name })));

export const vulnCount = (a) => VULN.filter((v) => v.asset === a).length;
export const tripleCount = (field, name) => TRIPLE.filter((u) => u[field] === name).length;

// SC10: an asset's zone can be narrowed by one step (outer -> field -> inner); narrowing
// changes which vulnerabilities in that asset are reachable, it does not close them.
export const NARROW = { outer: "field", field: "inner", inner: "inner" };
export function narrowedTriple(asset) {
  return VULN.reduce((n, v) => n + THREAT.filter((t) =>
    t.zone.includes(v.asset === asset ? NARROW[v.zone] : v.zone) && t.type.includes(v.type)).length, 0);
}
// security/count.mjs — three lists in one inventory: how many assets, threats, vulns, and valid triples.
import { ASSET, VULN, THREAT, TRIPLE, NARROW, vulnCount, tripleCount, narrowedTriple } from "./inventory.mjs";

const write = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join(""));
const cartesian = ASSET.length * THREAT.length * VULN.length;

console.log(`${ASSET.length} assets, ${THREAT.length} threats, ${VULN.length} vulns; ` +
  `cartesian product ${cartesian}, since each vuln is already tied to one asset the ` +
  `candidates are ${VULN.length * THREAT.length}, valid triples ${TRIPLE.length}`);

const A = [-21, 8, 8, 9, 14];
console.log("\n1. vulns and valid triples per asset");
write(A, "asset", "zone", "vulns", "triples", "triples/vuln");
for (const v of ASSET)
  write(A, v.name, v.zone, vulnCount(v.name), tripleCount("asset", v.name),
    vulnCount(v.name) ? (tripleCount("asset", v.name) / vulnCount(v.name)).toFixed(1) : "-");
write(A, "total", "-", VULN.length, TRIPLE.length, (TRIPLE.length / VULN.length).toFixed(1));

const B = [-26, 15, 8, 9];
console.log("\n2. how many threats can use each vuln");
write(B, "vuln", "type", "zone", "triples");
for (const v of [...VULN].sort((x, y) => tripleCount("vuln", y.name) - tripleCount("vuln", x.name)))
  write(B, v.name, v.type, v.zone, tripleCount("vuln", v.name));

const C = [-23, 8, 7, 9, 10];
console.log("\n3. reach and use per threat");
write(C, "threat", "zones", "types", "triples", "assets");
for (const t of THREAT)
  write(C, t.name, t.zone.length, t.type.length, tripleCount("threat", t.name),
    new Set(TRIPLE.filter((u) => u.threat === t.name).map((u) => u.asset)).size);

const D = [-48, 12, 9];
console.log("\n4. where the product narrows");
write(D, "step", "candidates", "left %");
const pct = (n) => ((n / cartesian) * 100).toFixed(1);
for (const [name, n] of [["asset x threat x vuln", cartesian],
  ["vuln already tied to one asset (vuln x threat)", VULN.length * THREAT.length],
  ["threat can reach that zone", VULN.reduce((a, x) =>
    a + THREAT.filter((t) => t.zone.includes(x.zone)).length, 0)],
  ["threat can use that vuln type", TRIPLE.length]]) write(D, name, n, pct(n));

const sorted = [...VULN].map((v) => tripleCount("vuln", v.name)).sort((x, y) => y - x);
const running = sorted.map(((s) => (n) => (s += n))(0));
console.log(`\nvuln order by triples carried: ${sorted.join(" ")}`);
console.log(`closing sum: ${running.join(" ")} (5 of 12 vulns close ${running[4]}/${TRIPLE.length}` +
  ` triples); vuln carrying zero triples: ` +
  VULN.filter((v) => tripleCount("vuln", v.name) === 0).map((v) => v.name).join(", "));

const E = [-21, 8, 9, 9, 9];
console.log("\n5. narrowing an asset's zone by one step (vuln count unchanged)");
write(E, "asset", "zone", "new", "triples", "closed");
for (const v of ASSET)
  write(E, v.name, v.zone, NARROW[v.zone], narrowedTriple(v.name), TRIPLE.length - narrowedTriple(v.name));
8 assets, 6 threats, 12 vulns; cartesian product 576, since each vuln is already tied to one asset the candidates are 72, valid triples 19

1. vulns and valid triples per asset
asset                    zone   vulns  triples  triples/vuln
reading-data            inner       1        2           2.0
billing-record          outer       1        2           2.0
work-order-queue        field       1        3           3.0
identity-store          inner       1        1           1.0
configuration           inner       2        2           1.0
audit-log               inner       2        1           0.5
meter-firmware          field       2        4           2.0
field-app               outer       2        4           2.0
total                       -      12       19           1.6

2. how many threats can use each vuln
vuln                                 type    zone  triples
unsigned-update                 integrity   field        3
unencrypted-transfer             transfer   field        3
outdated-library-version          version   outer        2
broad-read-permission          permission   inner        2
unvalidated-input                   input   outer        2
outdated-agent-version            version   outer        2
default-password               credential   inner        1
open-management-endpoint    configuration   inner        1
shared-account                 credential   inner        1
unretained-log                 visibility   inner        1
physical-access-point            physical   field        1
unvalidated-field                   input   inner        0

3. reach and use per threat
threat                    zones  types  triples    assets
external-opportunist          1      4        3         2
targeted-external             2      6        5         4
field-proximate               1      3        3         2
internal-user-error           2      2        2         2
malicious-insider             3      4        5         5
supply-chain                  2      2        1         1

4. where the product narrows
step                                              candidates   left %
asset x threat x vuln                                    576    100.0
vuln already tied to one asset (vuln x threat)            72     12.5
threat can reach that zone                                42      7.3
threat can use that vuln type                             19      3.3

vuln order by triples carried: 3 3 2 2 2 2 1 1 1 1 1 0
closing sum: 3 6 8 10 12 14 15 16 17 18 19 19 (5 of 12 vulns close 12/19 triples); vuln carrying zero triples: unvalidated-field

5. narrowing an asset's zone by one step (vuln count unchanged)
asset                    zone      new  triples   closed
reading-data            inner    inner       19        0
billing-record          outer    field       19        0
work-order-queue        field    inner       17        2
identity-store          inner    inner       19        0
configuration           inner    inner       19        0
audit-log               inner    inner       19        0
meter-firmware          field    inner       16        3
field-app               outer    field       18        1

Numbers belong to the measurement class; their inputs are SC6–SC9.

The Product Is Not a Path Count

The fourth table is this lesson’s central finding. Multiplying the lengths of the three lists gives 576. That number measures nothing, because the lists are not independent. The first narrowing is definitional: every vulnerability already lives in exactly one asset, so the asset dimension is not a separate factor — 72 candidates remain, 12.5% of the product. The second narrowing comes from reach: the threat has to reach the zone the vulnerability lives in, and the candidates drop to 42. The third comes from capability: the threat has to be able to use that vulnerability’s type, leaving 19 triples — 3.3% of the starting product.

The gap is not a difference of scale but of kind. The sentence “we have eight assets, six threat types, and twelve vulnerabilities” is an inventory; it says nothing about what could happen from where. Multiplying the three produces a scare number. What is actually countable is where the three intersect, and that intersection narrows under two conditions: reach and capability.

Still, the number 19 is not yet a path count. Every triple assumes the threat can touch the asset directly; the zone is given as a label, not counted as a gate to pass through. Reaching an asset in the inner zone actually requires passing over other assets first, and each of those crossings is a separate step. What this lesson leaves behind is an intersection count; the path count will be done in this topic’s last lesson.

Same Number of Vulnerabilities, a Fourfold Difference

The first table shows why vulnerability count alone is not an indicator. audit-log and field-app both carry two vulnerabilities each. The first produces 1 triple, the second 4. The ratio per vulnerability is 0.5 against 2.0 — a fourfold difference at the same vulnerability count.

The source of the difference shows up in the second table. field-app is in the outer zone and its vulnerabilities are of type input and version; two of the three threats that reach the outer zone can use those types. audit-log is in the inner zone and its vulnerabilities are of type visibility and input; of the three threats that reach the inner zone, only one uses visibility, and none use the input type.

The last row is this lesson’s sharpest item: the unvalidated-field vulnerability carries zero triples. The vulnerability is real, it sits in the list, it gets flagged in an audit — but no threat can reach it and use it. That does not mean the vulnerability should be left unpatched; if the zone boundary changes, the triple count stops being zero. What it means is this: vulnerability count is not an exposure measure. One of twelve vulnerabilities is exposed to nothing, and another is exposed to three at once.

A Threat’s Two Separate Widths

The third table measures threats on two axes: how many zones they reach and how many vulnerability types they can use. targeted-external reaches two zones but uses six types; malicious-insider reaches three zones and uses four types. Both produce five triples — the same number, by two different routes.

The difference is in the last column: targeted-external touches four separate assets, malicious-insider touches five. Reach width and capability width give the same triple total, but their spread differs. Capability width makes multiple vulnerabilities on the same asset usable; reach width touches more assets. A defense decision cannot be written without knowing which of the two it is narrowing.

supply-chain sits at the opposite end: it reaches two zones, uses two types, produces a single triple, and touches a single asset. This row records that the threat list’s length is not an indicator either — one of six threats carries one nineteenth of the inventory.

The last two lines rank the return on closing. When the twelve vulnerabilities are ordered by triple count, the sequence 3 3 2 2 2 2 1 1 1 1 1 0 comes out. Closing the five vulnerabilities that carry the most closes 12 of the 19 triples; the remaining seven triples need seven more separate vulnerabilities closed, and the twelfth adds nothing. Closing order is set not by vulnerability count but by triple count carried.

Which of the Three Lists Is Yours to Move

The fifth table tries a third lever. Closing a vulnerability shortens one list; the threat list cannot be shortened, because who is capable of what is not the organization’s decision to make. What remains is reach: narrowing an asset’s zone by one step changes the set of threats that can reach its vulnerabilities without closing any of them.

The results show four separate behaviors. When meter-firmware is pulled from field to inner, 3 triples close — equal to the highest return of closing a single vulnerability, and both of its vulnerabilities stay exactly where they are. work-order-queue closes 2, field-app closes

  1. The four assets already in the inner zone have no further step left to narrow, and the triples they close are zero.

The second row is the table’s most instructive item: when billing-record is pulled from outer to field, the triples closed are zero. The item has moved to a narrower zone, but its version-type vulnerability can be used both by a threat that reaches the outer zone and by another that reaches the field zone; a new triple opens exactly where one closed. The return on narrowing does not depend on how hidden the item now is, but on which set of threats is left outside.

The three levers are therefore not the same thing: closing a vulnerability deletes a row from the list, narrowing a zone leaves the same row in place and changes the set of threats that reach it, and the threat list is not yours to move at all. This is the last thing this lesson can count; the second lever’s real measure cannot be given without knowing how many steps sit between zones.

Summary

  • Asset is the thing protected, threat is the agent capable of causing harm, and vulnerability is the weakness in the asset; the three are separate lists and are counted separately.
  • The product of eight assets, six threats, and twelve vulnerabilities is 576; the valid-triple count is 19, or 3.3% of the product. The narrowing comes from two conditions: does the threat reach that zone, can it use that vulnerability type.
  • Nineteen triples are still not a path count; every triple assumes the threat touches the asset directly and does not count zone-to-zone crossings as steps.
  • Two assets carrying two vulnerabilities each produce 1 and 4 triples; one vulnerability carries zero triples, another carries three. Vulnerability count alone is not an exposure measure.
  • Of two threats that produce five triples each, one touches four assets and the other five; reach width and capability width give the same total with a different spread.
  • Narrowing an asset’s zone by one step, without closing any vulnerability, closes 3, 2, 1, or 0 triples; when other threats already reach the narrower zone, the return stays zero.

Next Step

This lesson counted nineteen triples and wrote every one of them at equal weight. But the single triple carried through physical-access-point does not occur at the same frequency as the three carried through unencrypted-transfer, nor does it cost the same when it does occur. In this lesson, closing order was set purely by triple count carried; yet an item that carries few triples can still be far heavier. The next lesson combines these two dimensions — probability and impact — over a set of items, and shows how two different scoring schemes rank the same list differently.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close