🔄 Topic

Two separate audit findings shared the same shape: a guard that computed the right answer and then did nothing with it. A personal-data policy that defaulted to allow, and a provider-authority check that only logged violations instead of blocking them. Both got turned from observers into enforcers.


🎯 Goal

Close the gap between “the system knows this is wrong” and “the system stops it” — in the two places an audit found that gap still open.


🛠 What I Did

I fixed both guards in the same remediation pass.

Main areas covered:

  • found that a standalone capability router returned approval_required: false for personal operations — calendar, contacts, birthdays — despite the tools clearly needing gating, with an unknown task type silently falling through to default-allow
  • extended the existing, already-tested permission gate instead of building a second router: personal-data tools (calendar, contacts, reminders, OAuth, email, external messaging) now always resolve to deny or ask, never silent allow, under any profile
  • confirmed unregistered tools already failed closed, and added an explicit regression test so a caller cannot forge approval-shaped arguments for a tool that does not exist
  • found separately that the router computed whether a candidate provider would widen authority or silently substitute cloud for a local-preferred task — and then routed to it anyway, only annotating the result afterward
  • gated every fallback substitution point through a shared authority check so a violating candidate is now rejected and recorded for audit, falling through to the existing fail-closed “unavailable” outcome
  • shipped the provider guard behind a feature flag defaulting off, confirmed byte-identical behavior when unset, so enforcement could be reviewed before it became live
  • honestly flagged what neither fix covered — “a provider can never widen authority” as a cross-cutting rule needs router changes this scoped repair did not make — rather than pretending the gap was closed

🔗 Key Cybersecurity Connections

A control that computes the right answer and does not act on it is not a control, it is a log line. Both bugs are the same failure mode: detection without enforcement. Real security engineering means checking, for every “guard,” whether its output actually gates anything downstream, or whether it just gets written down and ignored.

The honest partial-fix disclosure matters as much as the code: a hollow guard advertised as complete is worse than a documented gap, because the documented gap gets fixed next and the hollow guard gets trusted forever.


🔍 Investigation Questions

  • Does this guard’s computed result change what actually happens, or only what gets logged?
  • What does an unregistered or unknown case resolve to — deny, or a silent default?
  • Can a feature flag’s off-state be proven byte-identical to prior behavior before enabling it?
  • Is a partial fix documented as partial, or quietly presented as complete?
  • Are personal-data tools ever reachable through a path that bypasses the gate entirely?

🚨 Detection Opportunities

Checks for enforcement gaps:

  • a security-relevant computation whose result is never read by a decision point
  • personal-data tool categories resolving to allow under any profile
  • unknown or unregistered inputs defaulting to permissive behavior
  • a feature-flagged enforcement change with no test proving flag-off parity
  • a “PARTIAL” fix presented without its remaining gap documented

Example:

project=execution-policy
signal=guard_result_computed_but_not_enforced
risk_area=observe_only_control
triage=trace_guard_output_to_its_consuming_decision_point

🧭 MITRE ATT&CK Techniques

No direct mapping claimed. This is authorization and least-privilege enforcement design.


🗺 Visual Investigation Diagram

Guard computes: violation? yes/no
    ↓
Old behavior: log it, proceed anyway
    ↓
New behavior: gate every consuming decision point
    ↓
Violation → deny/ask, never silent allow
    ↓
Flag-off proven byte-identical before flag-on
    ↓
Remaining gaps documented, not hidden

⚠ Challenges

The provider-authority fix was the trickier one: two call sites computed the same check, and it would have been easy to gate one and miss the other, letting the policy drift apart over time. Sharing one function between both closed that risk structurally instead of by discipline.


📚 What I Learned

I learned to ask a new question of every guard I write: does its answer change anything? A check that only annotates is a check that only comforts.


➡ Next Steps

  • Audit the rest of the stack for other observe-only guards
  • Turn the provider-authority flag on by default once review is complete
  • Close the documented “provider can never widen authority” gap with the router changes it actually needs
  • Keep the shared-function pattern for any check enforced at multiple call sites

🧠 Reflection

Both bugs would have been invisible in a demo — the computed values looked correct, the logs looked right. Only asking “and then what happens” surfaced that nothing did.


🧩 Lessons Learned

What worked

Extending one already-tested gate instead of building parallel routers, and sharing one authority-check function across both call sites.

What broke

Two guards that computed correct answers and let the system proceed regardless.

Why it broke

Detection logic was written before enforcement logic, and enforcement was never added.

Fix / takeaway

For every guard, ask whether its result is enforced or merely observed — and flag partial fixes honestly instead of letting them look finished.


📈 Skill Progression Context

This supports my cybersecurity progression because the gap between detection and enforcement is one of the most common real-world audit findings, and closing it deliberately — twice, in one session — is direct practice for authorization design work.


😄 TL;DR

Found two guards that only watched. Now they both say no.