Introduction

Every chip that guards a secret — a smart card PIN, a device firmware lock, a cryptographic key — relies on one thing: the assumption that its instructions execute exactly as written. Fault-injection attacks shatter that assumption by bending the physics the chip runs on.

The technique is deceptively simple. An attacker pulses the supply voltage for a few nanoseconds, slows or speeds the clock for a single cycle, or fires a laser at a specific transistor. Any of these glitches can corrupt an instruction mid-flight, skip a branch, flip a bit in a register — and if the timing is right, the corrupted instruction happens to be the one that checks your PIN.

The chip does not know it was tampered with. It just skips the comparison, decides the check passed, and grants access. No secret was ever read directly; the attacker simply changed when and whether the check ran.

The countermeasure is equally elegant: run the critical check twice with independent hardware paths. If the two results disagree, something physical went wrong — abort and lock the device. This redundancy is the core of fault-tolerant security design, echoing the same ideas behind error-correcting codes and algorithm verification.

Glitch the Chip

Below is a simplified chip executing a PIN check. In Normal mode the check runs correctly. Press Inject Fault to fire a voltage glitch at the comparison instruction — with the right timing the chip skips it entirely and unlocks.

<!-- {{c_html_comment}} -->
<div class="panel">
  <div class="mode-bar">
    <label class="toggle-label">
      <input type="checkbox" id="redundancy-toggle">
      <span>{{lbl_redundancy}}</span>
    </label>
  </div>
  <div class="chip-view" id="chip-view">
    <div class="chip-title">{{lbl_chip}}</div>
    <div class="pipeline" id="pipeline">
      <div class="stage" id="stage-fetch">{{lbl_fetch}}</div>
      <div class="arrow">&#8594;</div>
      <div class="stage" id="stage-decode">{{lbl_decode}}</div>
      <div class="arrow">&#8594;</div>
      <div class="stage" id="stage-cmp" title="{{lbl_cmp_title}}">{{lbl_cmp}}</div>
      <div class="arrow">&#8594;</div>
      <div class="stage" id="stage-branch">{{lbl_branch}}</div>
      <div class="arrow">&#8594;</div>
      <div class="stage" id="stage-out">{{lbl_out}}</div>
    </div>
    <div class="path-row" id="path-row">
      <div class="path-box" id="path-a">
        <span class="path-label">{{lbl_path_a}}</span>
        <span class="path-result" id="path-a-result">—</span>
      </div>
      <div class="path-box" id="path-b">
        <span class="path-label">{{lbl_path_b}}</span>
        <span class="path-result" id="path-b-result">—</span>
      </div>
    </div>
    <div class="glitch-indicator" id="glitch-indicator">&#9889; {{lbl_glitch_active}}</div>
  </div>
  <div class="log" id="log"></div>
  <div class="controls">
    <button id="btn-normal" type="button">{{btn_normal}}</button>
    <button id="btn-glitch" type="button" class="danger">{{btn_glitch}}</button>
    <button id="btn-reset" type="button" class="ghost">{{btn_reset}}</button>
  </div>
  <div class="result-banner" id="result-banner"></div>
</div>
/* {{c_css_comment}} */
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: system-ui, sans-serif; font-size: 14px; color: #222; }
.panel { display: flex; flex-direction: column; gap: .6rem; padding: .6rem; }
.mode-bar { display: flex; align-items: center; gap: .5rem; }
.toggle-label { display: flex; align-items: center; gap: .5rem; cursor: pointer; font-weight: 600; font-size: .85rem; }
.toggle-label input { width: 36px; height: 20px; cursor: pointer; accent-color: #1d6fa8; }
.chip-view { background: #f0f4f8; border: 1.5px solid #c5d4e0; border-radius: 10px; padding: .7rem .8rem; display: flex; flex-direction: column; gap: .5rem; }
.chip-title { font-size: .75rem; font-weight: 700; color: #555; text-transform: uppercase; letter-spacing: .05em; }
.pipeline { display: flex; align-items: center; gap: .25rem; flex-wrap: wrap; }
.stage { background: #dce8f0; border: 1px solid #b0c8d8; border-radius: 6px; padding: .3rem .5rem; font-size: .78rem; font-weight: 600; color: #1d3557; min-width: 52px; text-align: center; transition: background .25s, border-color .25s; }
.stage.active { background: #1d6fa8; border-color: #155a8a; color: #fff; }
.stage.glitched { background: #e63946; border-color: #b52a33; color: #fff; animation: shake .25s; }
.stage.ok { background: #2a9d5c; border-color: #1e7a47; color: #fff; }
.arrow { color: #8fa8ba; font-size: 1rem; }
.path-row { display: flex; gap: .5rem; }
.path-box { flex: 1; background: #e8eef4; border: 1px solid #c0d0dc; border-radius: 6px; padding: .35rem .5rem; display: flex; justify-content: space-between; align-items: center; font-size: .8rem; }
.path-box.hidden { visibility: hidden; }
.path-label { font-weight: 600; color: #444; }
.path-result { font-weight: 700; color: #888; }
.path-result.pass { color: #2a9d5c; }
.path-result.fail { color: #e63946; }
.path-result.skip { color: #e09b00; }
.glitch-indicator { display: none; background: #fff3cd; border: 1px solid #e0a800; border-radius: 5px; padding: .2rem .5rem; font-size: .78rem; font-weight: 700; color: #856404; }
.glitch-indicator.visible { display: block; }
.log { background: #1a1a2e; color: #a0d8a0; border-radius: 7px; padding: .5rem .7rem; min-height: 4.5rem; max-height: 120px; overflow-y: auto; font: 12px/1.5 ui-monospace, monospace; }
.log .err { color: #ff7070; }
.log .warn { color: #ffd080; }
.log .info { color: #a0d8a0; }
.controls { display: flex; gap: .4rem; flex-wrap: wrap; }
button { font: 600 13px system-ui, sans-serif; padding: .4rem .8rem; border-radius: 7px; cursor: pointer; border: 1px solid #1d3557; background: #1d3557; color: #fff; }
button.danger { background: #c0392b; border-color: #922b21; }
button.ghost { background: #fff; color: #1d3557; }
.result-banner { min-height: 1.6em; font-size: .95rem; font-weight: 700; text-align: center; border-radius: 6px; padding: .3rem; }
.result-banner.unlocked { background: #fdecea; color: #c0392b; }
.result-banner.locked { background: #e8f5e9; color: #1e7a47; }
.result-banner.detected { background: #fff3cd; color: #856404; }
@keyframes shake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-4px)} 75%{transform:translateX(4px)} }
// Code not found

Now enable Dual Redundancy: the check runs on two independent paths. A glitch that corrupts one path leaves the other intact — the mismatch is detected and the device locks instead of granting access. Notice how the same glitch that worked before is now caught every time.

The Real Complexity

Fault injection sits at the intersection of physics and computation, which makes it both powerful and surprisingly hard to defend against:

  • The attacker's power: a glitch does not need to read any secret — it just needs to corrupt one instruction at the right moment. Voltage and clock glitches can be produced with cheap lab equipment; laser fault injection requires more setup but can target individual transistors.
  • The window is tiny: the attacker must glitch during the 5ns\sim 5\,\text{ns} window of the comparison instruction. Modern fault-injection rigs use oscilloscopes and trigger circuits to hit windows as short as a single clock cycle.
  • Simple redundancy: run the same check twice and compare results. A single-bit fault that flips the outcome of one check leaves the other unaffected; the mismatch triggers an alarm. This adds O(1)O(1) overhead in hardware but stops most single-fault attacks.
  • Stronger countermeasures: sensors (voltage monitors, clock monitors, light detectors) can detect a glitch before it corrupts anything. Error-correcting codes on registers catch bit-flips mid-computation. Formal verification of the hardware finite-state machine can prove that no single-fault deviation reaches an unlocked state.
  • Multi-fault attacks: an attacker who can inject two or more faults simultaneously — one to bypass the check and one to silence the alarm — can defeat simple redundancy. Defending against kk-fault attacks requires k+1k+1-redundant paths, at exponentially increasing hardware cost.

The fundamental tension: every extra layer of defense adds area, power, and latency to the chip. Security engineers must estimate the realistic attacker model and balance cost accordingly.

Where It Matters

Fault injection is not just a lab curiosity — it has broken real products and driven real engineering decisions:

  • Smart cards and SIM cards: early EMV payment chips were vulnerable to voltage glitches that bypassed the PIN check. Mandatory voltage sensors became a PCI security requirement.
  • Secure boot loaders: a clock glitch at the right moment can skip the signature verification that prevents unsigned firmware from running, giving an attacker full control of the device.
  • Cryptographic accelerators: faulting a single round of AES or RSA can leak the key through differential fault analysis (DFA) — the difference between a correct and a faulted ciphertext narrows the key search from 21282^{128} to a handful of candidates.
  • Secure enclaves: Intel SGX and ARM TrustZone were studied for fault-injection resistance; mitigations include hardware voltage monitors and software-level duplication of critical checks.
  • Satellite and space systems: cosmic rays cause natural single-event upsets that are equivalent to fault injection. The same redundancy techniques — triple modular redundancy (TMR), error-correcting RAM — defend against both attackers and radiation.

Fault injection teaches a broader lesson: any system that trusts its own computation without verification is one glitch away from failure. The defenses — redundancy, monitoring, error-correcting codes — are the same tools used wherever reliability matters under adversarial or noisy conditions.

Conclusion

Fault-injection attacks are a reminder that a chip is not just an abstract machine running abstract instructions — it is a physical object obeying the laws of physics, and those laws can be bent. A voltage spike lasting a few nanoseconds is enough to corrupt the one comparison that guards a secret, and the chip has no way to know it happened.

The answer is not to make chips impervious to physics — that is impossible. The answer is to make the outcome of a glitch detectable: run checks twice, monitor the supply rail, coat dies with light sensors, and use formal methods to prove that no reachable fault state grants access. Redundancy transforms a physical threat into a detectable anomaly.

Security, at the hardware level, is ultimately about the same principle that appears throughout computer science: one copy of a value is fragile, but two independent copies that must agree are robust. A fault that corrupts one leaves the other intact, and the disagreement is the alarm.

Share this article

Pick a channel — or use your device's native share sheet.

Comments

Loading comments...

https://www.kipuhub.com/en/article/fault-injection-attacks/Content licensed under CC BY-NC 4.0.