Cyberlium

Web › Module 10 › Lesson 1

BeginnerModule 10Lesson 1/5

Fail-Open vs Fail-Closed

A10: when checks error, do you deny or allow? Design the failure mode.

15 min+40 XP3 quiz
Module progress1 of 5

Visual · fail_open_closed

Gate stuck open vs stuck shut when the sensor dies. — router STOP — SAFE Choose fail-closed for authz on apps YOU own.

Opening

Exceptional conditions are when your security check throws — A10 asks what happens next.

OWASP Top 10:2025 A10 Mishandling of Exceptional Conditions covers unsafe fallbacks: authz service timeout → allow; certificate verify error → continue; feature flag store down → disable all checks. Attacker goal: induce errors that open doors. Cyberlium: name fail-open vs fail-closed for controls on systems YOU own — not crash foreign prod “to watch the fallback.” Practical commands: ; if it is a home router login, STOP and use SAFE http://The teaching toy shows broken fail-open vs fixed fail-closed. No hydra. No nmap. No DoS against strangers. Next: error messages that leak. Today: failure modes.

1. Fail-closed: deny when unsure for security decisions

For authentication and authorization, prefer fail-closed: if the policy engine errors, deny and log. Users see a safe unavailable message; attackers do not gain access from your outage. Document the choice per control on YOUR app. Prove it with curls to /broken/authz vs /fixed/authz on the 8775 toy.

Availability still matters — design timeouts, retries, and degraded read-only modes that do not skip authz.

Command guide

A10 Exceptions — Fail-closed

═══ INSTALL ═══

Linux (Debian/Ubuntu):

Command — copy this

sudo apt install curl

macOS: Built-in

Windows: Built-in (PowerShell: Invoke-WebRequest)

═══ COMMANDS ═══

Command — copy this

SAFE="http://127.0.0.1:8775"

Command — copy this

curl -sS -m 3 -D - "$SAFE/fixed/authz?boom=1" | head -n 18

2. Fail-open: when it is intentional and bounded

Some non-security features fail-open for UX (recommendations missing → empty list). Mixing that habit into authz is A10. If you must fail-open a secondary control, bound it: short TTL, alert, never for money movement or admin.

Write one intentional fail-open and one forbidden fail-open for your scope.

Command guide

A10 Exceptions — Fail-open

═══ INSTALL ═══

Linux (Debian/Ubuntu):

Command — copy this

sudo apt install curl

macOS: Built-in

Windows: Built-in (PowerShell: Invoke-WebRequest)

═══ COMMANDS ═══

Command — copy this

SAFE="http://127.0.0.1:8775"

Command — copy this

curl -sS -m 3 -I "$SAFE/" | head -n 12
curl -sS -m 3 -D - "$SAFE/broken/authz?boom=1" | head -n 16

3. Timeouts, defaults, and catch-all handlers

catch (Exception) { return true; } on a permission check is a classic fail-open. Default-allow flags in config are the same. Review YOUR code for broad catches around security decisions. Fix to deny + log + metric.

Circuit breakers should not short-circuit into allow for authz.

Command guide

A10 Exceptions — Timeouts, defaults, and catch-all handlers

═══ INSTALL ═══

Linux (Debian/Ubuntu):

Command — copy this

sudo apt install curl

macOS: Built-in

Windows: Built-in (PowerShell: Invoke-WebRequest)

═══ COMMANDS ═══

Command — copy this

SAFE="http://127.0.0.1:8775"

Command — copy this

curl -sS -m 3 -D - "$SAFE/broken/authz?boom=1" | head -n 18

4. Induced errors are an attacker technique — defend, do not practice on strangers

Attackers may flood dependencies to force fallbacks. Your defense is fail-closed design and capacity — not DoS labs against systems you do not own, and not hydra on the router. Cite A10. Original Cyberlium — not official OWASP certification.

chmod 600 notes.

5. Wrong vs right: allow-on-error vs deny-on-error for authz

Same word “fallback,” opposite safety.

  • Wrong

    catch-all returns allow. TLS verify failures ignored. Crash foreign prod to “test fallback.” Hydra 192.168.0.1. nmap the LAN. Bind 0.0.0.0.

  • Right

    Identify DEMO; router → SAFE 127.0.0.1:8775. Authz fail-closed; bounded non-security fail-open documented; lock fail-open-notes.txt. Next: Error Messages That Leak.

6. Hands-on: fail-closed toy on 8775 + fail-open-notes.txt

Start a10_fail_closed_toy.py (binds 127.0.0.1:8775). GET /broken/authz?boom=1 allows. GET /fixed/authz?boom=1 denies. Record. No foreign outage labs.

Command guide

fail_open_notes.sh — DEMO identify + fail-closed toy 8775

═══ INSTALL ═══

Linux (Debian/Ubuntu):

Command — copy this

sudo apt install curl
sudo apt install nmap
sudo apt install python3

macOS:

Command — copy this

brew install nmap
brew install python3

Windows: Built-in (PowerShell: Invoke-WebRequest)

Command — copy this

choco install nmap  # or download https://nmap.org/download.html

Download https://python.org/downloads/

═══ COMMANDS ═══

Command — copy this

cd "$HOME/cyberlium-lab"

Command — copy this

cat > a10_fail_closed_toy.py << 'PY'
"""Broken fail-open vs fixed fail-closed. Bind loopback only."""
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs

HOST = "127.0.0.1"  # bind only — never 0.0.0.0, never argv
PORT = 8775
if HOST != "127.0.0.1":
raise SystemExit("refusing non-loopback bind")

class Handler(BaseHTTPRequestHandler):
def log_message(self, fmt, *args):
    print("[demo]", fmt % args)

def _send(self, code: int, body: str):
    data = body.encode("utf-8")
    self.send_response(code)
    self.send_header("Content-Type", "text/plain; charset=utf-8")
    self.send_header("Content-Length", str(len(data)))
    self.end_headers()
    self.wfile.write(data)

def _boom(self, qs):
    return (qs.get("boom") or ["0"])[0] == "1"

def do_GET(self):
    u = urlparse(self.path)
    qs = parse_qs(u.query)
    if u.path == "/broken/authz":
        if self._boom(qs):
            return self._send(200, "ALLOW (fail-open on error) — insecure")
        return self._send(200, "allow owner")
    if u.path == "/fixed/authz":
        if self._boom(qs):
            return self._send(403, "DENY (fail-closed on error)")
        return self._send(200, "allow owner")
    return self._send(
        200,
        "Cyberlium A10 fail-closed toy. DEMO writeup: http://192.168.0.1/ "
        "GET /broken/authz?boom=1  GET /fixed/authz?boom=1",
    )

print("bind", HOST, PORT)
print("demo_writeup_url http://192.168.0.1/")
print("if 192.168.0.1 is a router, curl", f"http://{HOST}:{PORT}/")
HTTPServer((HOST, PORT), Handler).serve_forever()
PY

Command — copy this

cat > a10_l01_practical_commands.sh << 'SH'

echo; cat /tmp/a10_open.body; echo

echo; cat /tmp/a10_closed.body; echo

SH

Command — copy this

{

Mission: fail-open-notes.txt (mode 600)

1) 0.0.1:8775 after starting a10_fail_closed_toy.py.2) Run broken vs fixed authz curls. Document fail-closed for authz and any bounded fail-open for non-security features. 3) chmod 600 $HOME/cyberlium-lab/fail-open-notes.txt. No foreign outage labs. No hydra. No nmap.

Stuck? Ask Cyberlium AI Mentor

If “resilience” still means “allow when broken,” ask for a hint. Try: "Hint only: why authz should fail-closed; when fail-open is OK; why 192.168.0.1 router login is OUT OF SCOPE; where notes live?"

A10 starts with choosing deny when security checks cannot complete — proven on DEMO/SAFE 8775. Original Cyberlium — not official OWASP certification. Next — Error Messages That Leak.

Knowledge Check

1

APPLY: Policy service timeout currently returns allow. A10 issue?

Multiple choice

Knowledge Check

2

APPLY: True or False: catch (Exception) { return true; } around permission checks is safe.

True or False

Knowledge Check

3

APPLY: curl of http://192.168.0.1/ is router admin. Crash it to watch fail-open?

Multiple choice

← Previous

Answer all 3 knowledge checks to continue. (0/3 answered)