Skip to content
academia.sh

Lesson 14 / 22

Web Application Risks

Measuring that common risk lists are a way of reading, not a ranking: six of ten fictional items changing places between the overall ranking and the organizational ranking, the largest shift being four places, twenty-two of the thirty-nine steps across nine chains remaining uncontrolled, one chain never being breakable at runtime, and the defense's break order overlapping the organizational ranking in only one of three items.

Published Updated

In this lesson

  • Explains which criteria common risk lists rank by and why business impact is left out
  • Reorders the same item set with organizational weights and measures how many items change rank
  • Converts each risk item into a step sequence and counts the breakable link and the cost of a late break
Contents

The previous topic measured the human layer: from pretext to message, from message to domain, the chain’s first links rested on a decision made by a person, and that decision was measured by counting how many links it broke. Once the attacker is inside, though, the chain continues from somewhere else — from the links the software itself opens. This topic counts those links.

Before counting begins, there is a reading problem. Common lists prepared for application-layer risks exist, and in most organizations these lists are read like a to-do order. This lesson measures that way of reading: what the list is ranked by, why the ranking changes within an organization, and why a third ranking that none of the list’s items carries is needed. No technique in this lesson or this topic may be tried on a system outside written authorization and a defined scope; trying it is both illegal and unprofessional.

The Structure of the List

Common risk lists rank their items by four criteria: how often the item is seen in the field, how readily an attacker can exploit it, how readily the defender finds it, and the technical impact that results when it succeeds. All four belong to the item; none belongs to the organization.

One of the four criteria works in the opposite direction. The defender finding the item readily lowers the risk, because a readily found item is one with a high chance of being fixed. This is the criterion that feeds directly into the list’s order and is most often misread: an item being lower on the list does not mean it is rarely seen — it means it has already been found in most organizations. For an organization that has not done its own inventory, this information means nothing.

A fifth criterion is deliberately left out: business impact. What an item costs a given organization depends on what that organization protects, which work it considers unstoppable, and whether that item even has a counterpart in its architecture. The list cannot know this, so it does not account for it. The list’s order is therefore not a recommendation — it is a starting point.

TA1: the item set below is a model — not a real risk list, a real organization, or a real measurement; the criteria values are fictional. TA2: each item is a step sequence; controlled is the index of the steps that carry a control point. TA3: the overall ranking is the average of the four criteria. TA4: the organizational ranking uses the same criteria, sums the technical impact with its own weights, and scales an item that has no counterpart in its architecture by exposure. TA5: the breakable link is the lowest-indexed step that carries a control point.

// risk/item.mjs — fictional risk item set (model): not a real risk list, a real
// organization, or a real measurement. The four criteria are fictional values between 0..10.
// prev: prevalence, expl: exploitability, det: the defender's ease of detection,
// impact: technical impact component {c: confidentiality, i: integrity, a: availability}
export const ITEMS = [
  { name: "access-control",         prev: 9, expl: 7, det: 4, impact: { c: 9, i: 8, a: 3 }, exposure: 1.0 },
  { name: "injection",              prev: 6, expl: 8, det: 6, impact: { c: 9, i: 9, a: 5 }, exposure: 0.8 },
  { name: "identity-management",    prev: 7, expl: 6, det: 5, impact: { c: 8, i: 6, a: 4 }, exposure: 1.0 },
  { name: "configuration",          prev: 8, expl: 5, det: 8, impact: { c: 6, i: 5, a: 6 }, exposure: 1.0 },
  { name: "unmaintained-component", prev: 8, expl: 4, det: 9, impact: { c: 7, i: 7, a: 6 }, exposure: 1.0 },
  { name: "cryptographic-decision", prev: 5, expl: 3, det: 3, impact: { c: 9, i: 4, a: 1 }, exposure: 0.3 },
  { name: "logging-gap",            prev: 7, expl: 2, det: 2, impact: { c: 3, i: 3, a: 2 }, exposure: 1.0 },
  { name: "server-side-request",    prev: 3, expl: 5, det: 5, impact: { c: 7, i: 4, a: 3 }, exposure: 0.2 },
  { name: "design-flaw",            prev: 5, expl: 6, det: 2, impact: { c: 6, i: 8, a: 5 }, exposure: 0.9 },
  { name: "integrity-verification", prev: 4, expl: 4, det: 4, impact: { c: 4, i: 9, a: 4 }, exposure: 1.0 },
];

// TA2: each item is a step sequence. steps = number of steps in the chain;
// controlled = 1-based indices of the steps that carry a control point;
// cost = number of fictional items affected if the chain is only broken at the last step.
export const CHAIN = {
  "access-control":         { steps: 4, controlled: [2, 4],    cost: 240 },
  "injection":               { steps: 6, controlled: [2, 3, 5], cost: 480 },
  "identity-management":     { steps: 5, controlled: [1, 3, 4], cost: 180 },
  "configuration":           { steps: 3, controlled: [1, 2, 3], cost: 120 },
  "unmaintained-component":  { steps: 5, controlled: [1, 2],    cost: 300 },
  "cryptographic-decision":  { steps: 4, controlled: [4],       cost: 360 },
  "logging-gap":             { steps: 0, controlled: [],        cost: 0 },
  "server-side-request":     { steps: 5, controlled: [3, 4],    cost: 90 },
  "design-flaw":             { steps: 4, controlled: [],        cost: 200 },
  "integrity-verification":  { steps: 3, controlled: [2],       cost: 150 },
};

export const write = (w, ...s) => console.log(s.map((v, i) =>
  (w[i] < 0 ? String(v).padEnd(-w[i]) : String(v).padStart(w[i]))).join(""));
// risk/rank.mjs — the same item set ranked three different ways: overall list, org ranking,
// defense's break order. No randomness; every number is derived from fictional criteria values.
import { ITEMS, CHAIN, write } from "./item.mjs";

const overall = (k) => (k.prev + k.expl + (10 - k.det) + (k.impact.c + k.impact.i + k.impact.a) / 3) / 4;

// For the fictional measurement network, integrity and availability are heavy, confidentiality is lighter.
const W = { c: 0.1, i: 0.5, a: 0.4 };
const org = (k) => k.exposure * (k.prev + k.expl +
  (10 - k.det) + (k.impact.c * W.c + k.impact.i * W.i + k.impact.a * W.a)) / 4;

const rankBy = (f) => [...ITEMS].sort((a, b) => f(b) - f(a)).map((k) => k.name);
const OV = rankBy(overall), ORG = rankBy(org);
const A = [-24, 8, 6, 8, 6, 8];

console.log(`${ITEMS.length} fictional risk items, the same four criteria, two weight sets\n`);
write(A, "item", "overall", "rank", "org", "rank", "shift");
for (const name of OV) {
  const k = ITEMS.find((x) => x.name === name);
  const g = OV.indexOf(name) + 1, u = ORG.indexOf(name) + 1;
  write(A, name, overall(k).toFixed(2), g, org(k).toFixed(2), u,
    u === g ? "-" : (u < g ? "+" : "") + (g - u));
}
console.log(`\nitems that changed rank: ${OV.filter((name, i) => ORG.indexOf(name) !== i).length}` +
  `/${ITEMS.length}; largest shift: ` +
  `${Math.max(...OV.map((name, i) => Math.abs(ORG.indexOf(name) - i)))} places; shared in top three: ` +
  `${OV.slice(0, 3).filter((name) => ORG.slice(0, 3).includes(name)).length}/3`);

const B = [-24, 7, 12, 14, 11];
console.log(`\nchain columns (by org rank)`);
write(B, "item", "steps", "controlled", "first break", "late cost");
const chained = ORG.filter((name) => CHAIN[name].steps > 0);
for (const name of ORG) {
  const z = CHAIN[name];
  if (z.steps === 0) { write(B, name, "-", "-", "not a chain", "-"); continue; }
  write(B, name, z.steps, z.controlled.length,
    z.controlled.length ? `step ${z.controlled[0]}` : "unbreakable", z.cost);
}
const sum = (f) => chained.reduce((s, name) => s + f(CHAIN[name]), 0);
console.log(`\n${chained.length} chains, ${sum((z) => z.steps)} steps total, ` +
  `${sum((z) => z.controlled.length)} steps have a control, ` +
  `${sum((z) => z.steps - z.controlled.length)} steps have no control`);
const first = (name) => CHAIN[name].controlled[0] ?? 0;
console.log(`broken at step 1: ${chained.filter((a) => first(a) === 1).length}; ` +
  `step 3 or later: ${chained.filter((a) => first(a) >= 3).length}; ` +
  `never breakable: ${chained.filter((a) => first(a) === 0).length}`);

// Defense's order: earliest-breakable first, ties broken by higher cost.
const breakOrder = chained.filter((a) => first(a) > 0)
  .sort((a, b) => first(a) - first(b) || CHAIN[b].cost - CHAIN[a].cost);
console.log(`\ntop three by org rank   : ${ORG.slice(0, 3).join(", ")}`);
console.log(`top three by break order: ${breakOrder.slice(0, 3).join(", ")}`);
console.log(`shared items: ${ORG.slice(0, 3).filter((a) => breakOrder.slice(0, 3).includes(a)).length}/3`);
10 fictional risk items, the same four criteria, two weight sets

item                     overall  rank     org  rank   shift
access-control              7.17     1    7.03     1       -
injection                   6.42     2    5.08     6      -4
design-flaw                 6.33     3    5.76     3       -
identity-management         6.00     4    5.85     2      +2
configuration               5.17     5    5.13     4      +1
unmaintained-component      4.92     6    4.90     7      -1
cryptographic-decision      4.92     7    1.37     9      -2
logging-gap                 4.92     8    4.90     8       -
integrity-verification      4.92     9    5.13     5      +4
server-side-request         4.42    10    0.84    10       -

items that changed rank: 6/10; largest shift: 4 places; shared in top three: 2/3

chain columns (by org rank)
item                      steps  controlled   first break  late cost
access-control                4           2        step 2        240
identity-management           5           3        step 1        180
design-flaw                   4           0   unbreakable        200
configuration                 3           3        step 1        120
integrity-verification        3           1        step 2        150
injection                     6           3        step 2        480
unmaintained-component        5           2        step 1        300
logging-gap                   -           -   not a chain          -
cryptographic-decision        4           1        step 4        360
server-side-request           5           2        step 3         90

9 chains, 39 steps total, 17 steps have a control, 22 steps have no control
broken at step 1: 3; step 3 or later: 2; never breakable: 1

top three by org rank   : access-control, identity-management, design-flaw
top three by break order: unmaintained-component, identity-management, configuration
shared items: 1/3

Ranking Changes by Organization

The first table ranks the same ten items twice. The criteria values are the same in both rankings; what changes is only how the technical impact is summed and whether the item has a counterpart in this architecture. The result: six of the ten items changed rank, and the largest shift is four places.

Two extreme examples show where the difference comes from. injection is second in the overall ranking but drops to sixth in the organizational ranking; on part of the fictional measurement network’s endpoints, this item has no counterpart, and exposure scales it by 0.8. integrity-verification, by contrast, rises from ninth to fifth: proving that a meter reading is correct is this network’s actual job, and the integrity weight is 0.5. In the general list, this item sits in the middle ranks because, in an average organization, integrity does not weigh as heavily as confidentiality.

Exposure’s most visible effect on the list is in the cryptographic-decision item: from 4.92 to 1.37, from seventh to ninth. The cause is not weight but exposure: on this fictional network, the relevant surface is narrowly defined, and the score is scaled by 0.3. Exposure is a harsher multiplier than weight: weight moves an item a few places, exposure drops it off the list.

The direction of the shifts also carries information. Two of the three items that rise — identity-management and integrity-verification — are items that touch this network’s own work; of the three items that fall, two fall because of exposure, one because of weight. When an organization produces its own ranking, the real output it generates is not the order itself but the reason for the shift: if an item has no counterpart in the architecture, the effort spent tracking it is wasted; if it fell because of weight, the item is still there, and only its rank has changed.

Two items are shared in the top three. This does not mean the list is useless; it means the list correctly says which items exist but does not say which one comes first. The list is an inventory; the order is the organization’s own measurement.

Chain Columns

The second table names each item by this course’s three columns. There are a total of 39 steps across nine chains; 17 of them carry a control point, and 22 steps are uncontrolled. The number of uncontrolled steps is not a measure of the surface — it is a measure of the defense: every uncontrolled step is a point where the chain passes through cleanly.

Three chains can be broken at the first step. These are the three cheapest items: the chain ends before it starts, and the late-break cost is never paid. cryptographic-decision, by contrast, can only be broken at the fourth step, and by that point 360 fictional items have already been affected. The same item is ninth in the organizational ranking — meaning an item counted as low priority carries the second most expensive late-break cost.

Two rows in the table show the limit of the measure. design-flaw has four steps and carries no control point at any of them: this chain cannot be broken at runtime, because its control point lies outside the chain — at design time. For an item like this, the measure shifts from breaking to detection: the chain will complete; the only question left to ask is how late it will be seen.

The logging-gap row, meanwhile, is not even a chain. This item does not define an attack step sequence; it defines the invisibility of the other chains. Two different kinds of item stand side by side on the same list, and a single ranking shows both on the same scale. This is the most concrete problem with reading the list like a to-do order.

The Defense’s Third Ranking

The last three lines are the lesson’s conclusion. The organizational ranking gives risk from largest to smallest; the defense’s order, on the other hand, goes by the earliest breakable link. Only one item is shared between the top three of the two rankings.

unmaintained-component is seventh in the organizational ranking but first in the break order: its chain breaks at the first step, and its late-break cost of 300 is the third-highest value. In other words, an item that looks low priority is the cheapest and highest-return first move. access-control, in contrast, is first in both rankings, but its chain can only be broken at the second step; what decides whether something is the first move is not its place on the list but the place of its link.

The rule that follows from this governs the rest of this topic: prioritizing a risk item requires the answer to three separate questions — does the item exist in this architecture, how heavy is its impact in this organization, and at which step can its chain be broken. The list only supplies the inventory for the first.

The answer to the third question cannot be read from the list, because the list does not write out an item’s steps when it defines it. The remaining eight lessons of this topic fill exactly that missing column: each class’s step sequence is written out with its preconditions, the defense layers are mapped onto those steps, and the breakable link falls out as an index.

Summary

  • Common risk lists rank items by prevalence, exploitability, ease of detection, and technical impact; they deliberately leave out business impact. The list is not an ordering recommendation — it is an inventory.
  • When the same ten items were reordered with organizational weights and exposure, 6 items changed rank, the largest shift was 4 places, and only 2 items stayed shared in the top three.
  • Exposure is a harsher multiplier than weight: one item dropped from 4.92 to 1.37 and fell to the bottom of the list; weight changes moved items by at most four places.
  • Across nine chains, 17 of 39 steps carry a control point, and 22 steps are uncontrolled. Three chains break at the first step; one chain can never be broken at runtime, and there the measure shifts to detection.
  • The top three of the organizational ranking and the top three of the break order overlap in only 1 item; an item ranked seventh becomes the first move because it breaks at the first step.

Next Step

This lesson counted the items but opened none of them up. Among the ten items, the chain carrying the highest late-break cost had six steps and three of them carried a control point — which three, and which step those controls cut off, was not written. The next lesson opens that chain: the injection class’s six steps are written out one by one with their preconditions, the same input set is run through five defense layers, and the step each layer breaks is counted. What gets measured is not the input itself, but which layer the input stops at, and, when it does not stop, how far into the chain it advances.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close