Skip to content
academia.sh

Lesson 04 / 17

Asset and Inventory Management

When six off-inventory assets are added to the list, the 47-item list grows to 69 items and the 5,768.61-unit total rises to 8,045.45 fictional units: off-inventory items carry 28.3 percent of the true risk, 41 recorded items change rank, the largest shift is 22 positions, six shadow items enter the top twenty, 8 of the 30 shadow items can never enter any ranking because their value was never written, and the shadow item that rises to the highest rank comes from an asset no discovery source has ever seen.

Published Updated

In this lesson

  • Counts the risk items produced by off-inventory assets and calculates their share of the true total
  • Ranks two lists side by side: how many items in the incomplete list end up in the wrong position, and by how many places
  • Measures the unit cost of discovery sources and the risk carried by the asset no source ever sees
Contents

Across three lessons the same list was ranked, measured and budgeted: 47 items, ten assets, seven threats. Every calculation assumed this list was complete. Yet the list was derived from an inventory, and an inventory is a set of records — an asset that was never recorded cannot enter the list.

An unrecorded asset’s risk is not zero; it is unwritten. It is invisible in the ranking, takes no place in the budget, is not even counted as accepted — because acceptance requires at least a record. This lesson counts that gap: how many assets sit outside the inventory, how many items they produce, how many ranking positions would change if they entered the list, and what the unit cost of finding them is.

Left Outside the Inventory

An off-inventory asset is not usually a rule violation; more often it is the residue of ordinary operations: a server spun up for a test and never torn down, a cloud account a team opened on its own budget, a transfer service the field team set up itself, a branch endpoint that was decommissioned but never unplugged, a second supplier connection, a backup data copy. Each one exists because it served some purpose, and none of them was set up with updating the inventory in mind.

The way to find them is discovery sources, and each source looks from a different angle. Network scanning sees what is addressable, identity records see what has an account, billing records see what generates a cost, the configuration repository sees what is defined, the endpoint agent sees what has software running on it. An asset is as findable as the number of sources it appears in; if it appears in none, it cannot be found.

  • RM17. The seven threats and their coefficients are the same as in the previous lessons; the unit is the fictional unit.
  • RM18. The five discovery sources, their costs and source masks are a model; no real scan is performed.
  • RM19. The six off-inventory assets are a model. The ? mark shows that the asset has been found but its value has not been written.
  • RM20. An item’s risk can only be calculated if the asset’s value has been written; an asset whose value is unwritten cannot enter any ranking even if it is discovered.
  • RM21. Discovery is one-time and puts the asset it finds into the inventory; entering the inventory does not mean the value has been written.
  • RM22. Off-inventory assets are written with higher exposure multipliers than recorded assets; the model’s rationale is that maintenance and hardening work is applied only to recorded assets.
// risk/inventory.mjs — assets in the inventory and off-inventory assets. THIS IS A MODEL; no real
// scan is performed, no real account is opened, every value is in "fictional units".

// RM17: threat row: name | annual baseline frequency | exposure ratio
export const THREAT = `
  credential-theft     0.30  0.35
  malicious-code       0.50  0.25
  misconfiguration     0.80  0.15
  insider-misuse       0.10  0.40
  service-disruption   0.40  0.20
  physical-access      0.06  0.50
  supply-chain         0.08  0.45`
  .trim().split("\n").map((r) => { const [name, s, m] = r.trim().split(/\s+/);
    return { name, baseFreq: +s, exposureRatio: +m }; });

// RM18: discovery source: name | annual cost. Every asset carries a source mask.
export const SOURCE = `
  network-scan         35
  identity-record      15
  billing-record       10
  config-repository    25
  endpoint-agent       45`
  .trim().split("\n").map((r) => { const [name, b] = r.trim().split(/\s+/);
    return { name, cost: +b }; });

// RM19: asset row: name | value ('?' value not written) | exposure | threat mask |
// source mask | in inventory. The ten assets in the inventory are already recorded.
const ROW = `
  field-laptop            900  1.6  1111011  11001  E
  branch-endpoint         600  1.2  1111110  10011  E
  measurement-collector   750  1.4  0111110  10010  E
  processing-server      1800  0.6  1111101  11011  E
  perimeter-network      1200  1.8  0011100  10010  E
  identity-directory     2400  1.0  1011100  01010  E
  cloud-account          2000  1.5  1011100  01100  E
  subscriber-database    3000  0.4  1011100  00011  E
  field-application      1400  1.1  1111001  00110  E
  supplier-connection    1000  1.3  1001101  01100  E
  temporary-test-server   800  1.7  1111101  11010  H
  team-cloud-account        ?  1.6  1011100  01100  H
  field-transfer-service  700  1.9  1111011  10001  H
  retired-branch-endpoint 500  1.5  1111110  10010  H
  third-supplier-endpoint   ?  1.4  1001101  01100  H
  backup-data-copy       2200  0.8  1011100  00000  H`;

export const ASSET = ROW.trim().split("\n").map((r) => {
  const [name, v, m, mask, km, inv] = r.trim().split(/\s+/);
  return { name, value: v === "?" ? null : +v, exposureMult: +m, mask, sourceMask: km,
    inInventory: inv === "E", visible: km.includes("1") };
});
export const RECORDED = ASSET.filter((v) => v.inInventory);
export const SHADOW = ASSET.filter((v) => !v.inInventory);

// RM20: an item's risk can only be calculated if the asset's value has been written; an asset
// whose value is unwritten cannot enter any ranking even if it is discovered.
export const ALL = ASSET.flatMap((v) => THREAT
  .filter((_, j) => v.mask[j] === "1")
  .map((t) => ({ v, t, risk: v.value === null ? null : +(t.baseFreq * v.exposureMult * v.value * t.exposureRatio).toFixed(2) })));
export const REC = ALL.filter((k) => k.v.inInventory);
export const SHA = ALL.filter((k) => !k.v.inInventory);
export const rank = (L) => L.filter((k) => k.risk !== null)
  .map((k, i) => ({ k, i })).sort((a, b) => b.k.risk - a.k.risk || a.i - b.i).map((x) => x.k);
export const sum = (L) => +L.reduce((a, k) => a + (k.risk || 0), 0).toFixed(2);

Counting the Two Lists

// risk/missing.mjs — how the ranking would change if off-inventory items entered the list
import { RECORDED, SHADOW, SOURCE, ALL, REC, SHA, rank, sum } from "./inventory.mjs";

const y = (g, ...s) => console.log(s.map((v, i) =>
  (g[i] < 0 ? String(v).padEnd(-g[i]) : String(v).padStart(g[i]))).join("").trimEnd());
const S1 = rank(REC), S2 = rank(ALL);
const position = (L, k) => L.indexOf(k) + 1;

console.log(`${RECORDED.length} assets / ${REC.length} items / ${sum(REC)} fictional units are in the inventory; ` +
  `${SHADOW.length} off-inventory assets / ${SHA.length} items / ${sum(SHA)} units ` +
  `(${((sum(SHA) / sum(ALL)) * 100).toFixed(1)} percent of the true total)`);

const A = [-23, 7, 7, 10, 10, 10];
console.log("\n1. off-inventory assets");
y(A, "asset", "value", "items", "risk", "sources", "status");
for (const v of SHADOW) {
  const ks = SHA.filter((k) => k.v === v);
  y(A, v.name, v.value ?? "?", ks.length, v.value === null ? "-" : sum(ks).toFixed(2),
    v.sourceMask.split("").filter((c) => c === "1").length,
    v.value === null ? "valueless" : v.visible ? "visible" : "unseen");
}
const scorable = SHA.filter((k) => k.risk !== null);
console.log(`${scorable.length} of the ${SHA.length} off-inventory items are scorable ` +
  `(${sum(scorable).toFixed(2)} units), ${SHA.length - scorable.length} cannot enter any ranking ` +
  `because their value was never written`);

const B = [-38, 9];
console.log("\n2. what changes when the full list is ranked");
const shift = REC.map((k) => Math.abs(position(S1, k) - position(S2, k)));
y(B, "inventory list / full list items", `${S1.length} / ${S2.length}`);
y(B, "total risk", `${sum(REC).toFixed(2)} / ${sum(ALL).toFixed(2)}`);
y(B, "recorded items with a changed rank", shift.filter((x) => x > 0).length);
y(B, "largest rank shift", Math.max(...shift));
y(B, "off-inventory items in top ten",
  S2.slice(0, 10).filter((k) => !k.v.inInventory).length);
y(B, "highest off-inventory item's rank",
  Math.min(...scorable.map((k) => position(S2, k))));
y(B, "off-inventory items in top twenty",
  S2.slice(0, 20).filter((k) => !k.v.inInventory).length);

const C = [-22, -21, 10, 9, 6];
console.log("\n3. the full list's top ten");
y(C, "asset", "threat", "risk", "source", "rank");
for (const k of S2.slice(0, 10))
  y(C, k.v.name, k.t.name, k.risk.toFixed(2), k.v.inInventory ? "recorded" : "shadow", position(S1, k) || "-");

const D = [-21, 7, 8, 13, 8, 9];
console.log("\n4. per discovery source (off-inventory assets only)");
y(D, "source", "cost", "assets", "risk opened", "items", "ratio");
const opened = (f) => { const vs = SHADOW.filter(f);
  const ks = SHA.filter((k) => vs.includes(k.v) && k.risk !== null);
  return { vs, ks, r: sum(ks) }; };
for (const [i, s] of SOURCE.entries()) {
  const a = opened((v) => v.sourceMask[i] === "1");
  y(D, s.name, s.cost, a.vs.length, a.r.toFixed(2), a.ks.length, (a.r / s.cost).toFixed(3));
}
const all5 = opened((v) => v.visible);
const cost = SOURCE.reduce((a, s) => a + s.cost, 0);
y(D, "all five combined", cost, all5.vs.length, all5.r.toFixed(2), all5.ks.length,
  (all5.r / cost).toFixed(3));
const blind = SHADOW.filter((v) => !v.visible);
console.log(`assets no source ever sees: ${blind.length}, items ` +
  `${SHA.filter((k) => blind.includes(k.v)).length}, risk ` +
  `${sum(SHA.filter((k) => blind.includes(k.v))).toFixed(2)} units`);
10 assets / 47 items / 5768.61 fictional units are in the inventory; 6 off-inventory assets / 30 items / 2276.84 units (28.3 percent of the true total)

1. off-inventory assets
asset                    value  items      risk   sources    status
temporary-test-server      800      6    688.16         3   visible
team-cloud-account           ?      4         -         2 valueless
field-transfer-service     700      6    606.48         2   visible
retired-branch-endpoint    500      6    375.00         2   visible
third-supplier-endpoint      ?      4         -         2 valueless
backup-data-copy          2200      4    607.20         0    unseen
22 of the 30 off-inventory items are scorable (2276.84 units), 8 cannot enter any ranking because their value was never written

2. what changes when the full list is ranked
inventory list / full list items        47 / 69
total risk                            5768.61 / 8045.45
recorded items with a changed rank           41
largest rank shift                           22
off-inventory items in top ten                1
highest off-inventory item's rank             7
off-inventory items in top twenty             6

3. the full list's top ten
asset                 threat                     risk   source  rank
cloud-account         misconfiguration         360.00 recorded     1
cloud-account         credential-theft         315.00 recorded     2
identity-directory    misconfiguration         288.00 recorded     3
perimeter-network     misconfiguration         259.20 recorded     4
identity-directory    credential-theft         252.00 recorded     5
cloud-account         service-disruption       240.00 recorded     6
backup-data-copy      misconfiguration         211.20   shadow     -
field-application     malicious-code           192.50 recorded     7
identity-directory    service-disruption       192.00 recorded     8
field-application     misconfiguration         184.80 recorded     9

4. per discovery source (off-inventory assets only)
source                  cost  assets  risk opened   items    ratio
network-scan              35       3      1669.64      18   47.704
identity-record           15       3       688.16       6   45.877
billing-record            10       2         0.00       0    0.000
config-repository         25       2      1063.16      12   42.526
endpoint-agent            45       1       606.48       6   13.477
all five combined        130       5      1669.64      18   12.843
assets no source ever sees: 1, items 4, risk 607.20 units

The numbers are in the measurement class; its inputs are RM17–RM21.

The Missing List’s Share

Six off-inventory assets produce 30 risk items, and the risk they carry is 2,276.84 fictional units. The true total is not 5,768.61 but 8,045.45 units; the off-inventory share is 28.3 percent. Every ranking, every budget calculation and every acceptance decision made across three lessons was given under the assumption that this share did not exist.

The number matters not only because it is large but because of its distribution. The backup data copy alone carries 607.20 units and outweighs six of the ten assets in the inventory. The temporary test server, at 688.16 units, outweighs eight of those ten. What they have in common is a low value — but a low value multiplied by a high exposure does not produce a small number.

The exposure multiplier column explains this height, and it is a deliberate choice in the model (RM22): off-inventory assets take values between 0.8 and 1.9, recorded assets between 0.4 and 1.8. The rationale is simple and self-reinforcing — hardening, patching and monitoring work is applied to the list in the inventory, and an asset that is not on the list receives none of it. Being unrecorded means not only invisibility but also neglect; the two effects multiply in the same direction.

Where the Ranking Shifts

The second table answers the real question. The incomplete list ranks 47 items, the full list ranks 69; 41 recorded items change rank and the largest shift is 22 positions. Six shadow items enter the top twenty, and one of them rises to seventh place.

The third table names this item: misconfiguration on the backup data copy, seventh on the list at 211.20 units, and it does not exist in the inventory list at all. When it enters, the malicious-code item on the field application drops from seventh to eighth, and every item below it moves down one place. If the budget handles the first ten items, a program working from the incomplete list never opens this item at all — and it does not even know this is a gap, because the item is not on the list and so does not appear in the “not handled” column either.

The size of the shift is tied to how flat the list’s distribution is. When the risk distribution is flat, 22 new items scatter throughout it and change nearly every item’s position. If there had been a sharp peak, the new items would pile up at the bottom and the top ten would not change. Here the top ten does change, which means the gap reaches the region where decisions are made.

Being Found and Being Counted Are Not the Same

The first table’s last column writes a second distinction. Two of the six assets — the cloud account the team opened and the third supplier endpoint — appear in two separate sources, but their values were never written. These two assets produce 8 risk items, and none of those items can be scored: no value means no impact, and no impact means no risk can be calculated. 22 of the 30 shadow items are scorable, 8 are not.

This is the half of inventory work that gets missed most often. Discovery records that an asset exists; the inventory records what it is — who owns it, what work it carries, what happens if it goes down. The first can be automated, the second requires a person to make a judgment. An asset that has been found but whose value was never written ends up in the same place as an asset that was never found at all: neither enters any ranking. The only difference between them is that the first one’s name is on a list somewhere.

Discovery’s Unit Cost

The fourth table tests discovery against the course’s unit of measure. Network scanning opens three assets and 1,669.64 units of risk for 35 units; its ratio of 47.704 is the highest on the list. Identity records open 688.16 units for 15 units (45.877). Billing records find two assets for 10 units and open 0.00 units — the two assets they find have no value written, so the scorable risk they open is zero.

The last row tests the sum. All five sources together find five assets for 130 units, but the risk they open is still 1,669.64 units — the number network scanning opens on its own. The remaining four sources spend 95 more units and add nothing to the scorable risk; the two assets they add stay valueless. The return per unit falls from 47.704 to 12.843. Adding a discovery source always finds more items, but if the item it finds cannot be scored, it does not enter the ranking and takes no place in the budget.

The final line writes the lesson’s harshest number: there is an asset no source ever sees, carrying 4 items and 607.20 units. Even if all five sources were bought, it would not be found. And the item in seventh place on the full list comes from exactly this asset. Discovery coverage is not a lid, it is a threshold: everything that falls below it goes unmeasured, and everything unmeasured is counted as accepted by default.

Summary

  • Six off-inventory assets carry 30 items and 2,276.84 fictional units; the true total is 8,045.45 units and the off-inventory share is 28.3 percent.
  • When the full list is ranked, 41 recorded items change position, the largest shift is 22 places; six shadow items enter the top twenty and one rises to seventh.
  • A program working from the incomplete list cannot even see that it has not handled this item: because the item is not on the list, it is not in the “not handled” column either.
  • Being found and being counted are not the same thing. Two shadow assets appear in two sources but their value was never written; 22 of the 30 shadow items are scorable, 8 can never enter any ranking.
  • Network scanning gives a ratio of 47.704 for 35 units; all five sources together open the same risk for 130 units and the ratio falls to 12.843. Adding sources finds more assets, not more scorable risk.
  • An asset no source ever sees carries 4 items and 607.20 units; the item in seventh place on the full list comes from this asset.

Next Step

Every discovery source assumes one thing in common: the asset being sought leaves a trace in the organization’s own network, its own identity system, or its own billing. A server sitting in a supplier’s own systems leaves none of these traces. Network scanning never reaches it, the endpoint agent never runs on it, the configuration repository does not recognize it. All that stands in the organization’s place for those assets is a contract clause and an assessment questionnaire. The next lesson measures this across a set of three suppliers: how many controls the contract states, how many the questionnaire actually proves, and how many items remain that look delegated but cannot be verified.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close