Known limitations 

Nothing on this page is hedging. A control whose boundary is undocumented gets trusted past its boundary, and that is how a hardening feature turns into a liability.

A compromised PHP process can request every secret 

The limitation. Arbitrary code execution in the TYPO3 PHP process — an RCE, a malicious extension, a hostile Composer dependency, a compromised deployment — defeats every control in this extension. The attacker is inside the trust anchor: they can call VaultService::retrieve() , or load the master key provider directly, and take whatever the process may legitimately take.

Why it cannot be fixed here. nr-vault runs in that process. A control implemented in the same address space as its attacker is not a control.

What actually helps. Moving decryption out of the process, so that a compromise yields a request-rate-limited oracle instead of the key. That is a different architecture, evaluated in ADR-016: Sidecar daemon option, and it is not what this extension is today.

What still holds. Attribution. A read performed by compromised code still writes an audit row, and with a KMS every unwrap is logged by a system the attacker does not control. Detection after the fact is a genuinely different thing from prevention — just not a substitute for it.

The typo3 provider does not separate the vault from TYPO3 

The limitation. The default provider derives the master key from $GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey'] with HKDF-SHA256. The derivation is sound, but it changes nothing about custody: anyone who can read config/system/settings.php can derive the master key. That includes every backup of the configuration directory, every developer with a copy of the production settings, and every process running as the web-server user.

Its strength also cannot exceed the strength of encryptionKey itself. The provider refuses source keys shorter than 32 characters, but a weak-but-long key still yields a weak master key.

Consequence for backups. A dump of the database plus the configuration directory is a complete break. See Backup and restore.

What to do. Use file, env or transit for anything holding production credentials. The hardened profile enforces this: typo3 is rejected outright with exception code 1753900002, and there is no auto-detection fallback that could quietly put you back on it.

Revealed plaintext in the browser cannot be zeroized 

The limitation. JavaScript strings are immutable and garbage-collected. Setting input.value = '' removes the value from the DOM; it does not remove the engine's copies from memory. There is no browser API that would.

What is actually provided. A bounded exposure window, not secure deletion: 30 seconds of visibility, plus an immediate wipe when the tab is hidden (visibilitychange) or the page goes away (pagehide). Nothing is cached client-side, so a revealed value does not survive a modal close, and the response is marked Cache-Control: no-store.

The clipboard is worse. Clipboard contents outlive the dialog, outlive the page, and cannot be cleared reliably from JavaScript — they may also synchronise to other devices. That is why the hardened profile disables the copy button entirely rather than clearing the clipboard on a timer, which would be theatre.

The hash chain does not prevent a database reset 

The limitation. The HMAC chain proves that no row was altered within the stored chain. It cannot prove that the chain is still the same chain. An attacker with DELETE rights on tx_nrvault_audit_log can truncate it and let the service build a fresh, internally consistent chain from uid 1 — the chain itself cannot distinguish that from a genuinely young installation.

What closes the gap, partially. Two chain-tip anchors, at different distances from the attacker.

The in-database anchor (ADR-034: Audit chain tip anchor) records "row uid=A still exists with entry_hash=H" in sys_registry, MACed under a key derived from the master key — which is not in the database. Truncating the audit table alone therefore no longer looks like a young installation: the anchor still names a row that is gone, and verification reports a violation.

The external anchor is published to a store the database owner does not control at all, giving verification two facts to check that no database write can reach: the chain cannot have shrunk, and the row at the anchored sequence must still hash to the anchored tip.

What remains. Detection, not prevention — and each anchor only as far as its storage is trustworthy. An attacker who also holds DELETE on sys_registry can remove the in-database anchor, which then reads as "not armed" rather than as a violation; auditAnchorRequired is what closes that, turning a missing anchor into a critical finding a database writer cannot silence. It lives in the extension configuration, so a database-write attacker cannot reach it — but unlike disableAdminOverride it accepts no $TYPO3_CONF_VARS pin, so a compromised administrator can still clear it from the Settings module. An anchor file on a host the attacker owns can likewise be truncated, so anchors shipped off-host through syslog or a webhook are what makes the external property real. And in every case: tamper-evident, not tamper-proof.

A KMS protects custody, not runtime 

The limitation. With the transit provider the master key is unwrapped by HashiCorp Vault on demand and only the wrapped ciphertext sits locally. That is a genuine improvement in custody, rotation and auditability. It does not stop a live attacker inside the request: the process holds a token it may legitimately use, so it can call decrypt and obtain the master key exactly as the vault does.

What it buys, precisely. Key custody and rotation move into Vault; every unwrap is centrally audited and revocable, so pulling the token or the policy locks the vault out immediately with no key file left to recover; and a stolen database plus a stolen webroot is useless without Vault access.

What it costs. Availability. An unreachable Vault is an unreadable vault.

Backups need the database and separately stored key material 

The limitation. A database backup alone cannot be restored into a working vault — the ciphertext is undecryptable without the master key. A backup of both, stored together, is a single artefact that contains everything.

Both failure modes are real, and they pull in opposite directions. Storing key material with the dump destroys the protection; storing it nowhere destroys the data. The only correct answer is: back up both, store them separately, restore both, and verify the restore with a probe decrypt. See Backup and restore.

Master key loss is data loss 

The limitation. There is no recovery path, no escrow, no vendor-side reset. If the master key is lost, every secret in the vault is permanently unreadable. This is not a limitation to be engineered away — a vault with a recovery backdoor is a vault with a backdoor.

The typo3 provider makes this easier to trip over than it looks: rotating TYPO3's encryptionKey changes the derived master key and orphans every stored secret. Treat encryptionKey as vault key material for as long as that provider is configured.

Break-glass restores full admin power 

The limitation. While a break-glass window is open, an administrator has exactly what they had before the override was disabled: every operation permission, and read, write and delete on every secret. Break-glass prevents nothing.

Its value is evidence and time boxing — a named actor, a mandatory typed justification, a hash-chained audit row written before the window opens, a PSR-14 event observers can alert on, a banner every operator sees, and an expiry between 1 and 60 minutes that nobody has to remember, evaluated at read time on every access-control decision.

Two gaps worth naming. A window that simply expires writes no audit row — nothing runs at the moment it lapses, so reconstruct the closed interval from the activation row's expiresAt context value. And an administrator with filesystem access can unpin disableAdminOverride instead of using break-glass at all; that path is visible in the filesystem, not in the audit log.

Treat an activation as an incident to review, not as routine maintenance (Incident response).

Metadata is not confidential 

Identifiers, ownership, group tiers, timestamps, version counters and the whole audit trail are stored unencrypted. The audit log is the sensitive one: it maps who holds which credential and when they use it, which is a useful target in its own right. That is why audit.view and audit.export are separate permissions, and why an export — which leaves the tamper-evident store behind, with no hash chain, no retention policy and no further access control — is gated apart from viewing.

Out of scope entirely 

nr-vault makes no claim about, and provides no control over:

  • the operating system, the web server, the PHP runtime and its extensions;
  • the database server, its access control, its backups and its replicas;
  • TYPO3 core authentication, session handling and CSRF (inherited, not provided);
  • the browser, the clipboard, screenshots, screen sharing and cameras;
  • the SIEM or log pipeline once evidence has left the process;
  • physical and network security, and the trustworthiness of every other installed TYPO3 extension.

Target of evaluation states the same boundary in the form an assessor needs.