Set Up Claude Code Guardrails

Configure permission rules, hooks, and CLAUDE.md to secure Claude Code.

Introduction

⚡️ 30 Second Summary

When you give an AI agent access to your terminal and files, you need to make sure it cannot accidentally delete critical data, leak secrets, or run dangerous commands.

In this project, you will configure three layers of Claude Code security: permission deny rules that block access to sensitive files, hooks that intercept and validate every action, and a CLAUDE.md policy that sets coding rules. You will then red-team your setup to verify each layer works.

What You'll Build

You will build a defense-in-depth security configuration for Claude Code that combines permission deny rules, deterministic hook scripts, and an advisory policy file to protect a sample project from unsafe AI actions.

By the end of this project, you'll have:

  • 🔒 A .claude/settings.json with permission deny rules blocking access to .env, secrets/, and dangerous commands.
  • 🪝 Two hook scripts that validate file edits and Bash commands before Claude can execute them.
  • 💎 Secret Mission: Red-team your guardrails and write a CLAUDE.md security policy.

Want a complete demo of how to do this project, from start to finish? Check out our 🎬 walkthrough with Maximus

Do I need to pay to do this project?

This project requires a Claude Pro ($20/month) or Max ($100/month) subscription for Claude Code access. All other tools are free and open source.

Not sure if this project is right for you? Check if it matches your goals

If you're up for a bit of a challenge, quiz yourself on the key concepts up ahead in this project.

Get Your Tools Ready

In this step, you will install the tools you need and create a sample project folder with intentionally sensitive files. These files will act as your "test dummies" for the security rules you build later.

In this step, get ready to:

  • Set up Claude Code.
  • Install jq.
  • Create your sample project with sensitive files.

Open Your Terminal

🍎 macOS

  • Press Command + Space, type Terminal, and press Enter.

🖼️ Windows

  • Press the Windows key, type Terminal, and press Enter.

Set Up Claude Code

  • Run this command to check if Claude Code is already installed:
claude --version

✔️ I see a version number

You are all set. Claude Code is already installed.

ⓧ Command not found

You need to install Claude Code. Select your operating system below:

🍎 macOS / Linux

  • Run this command to install Claude Code:
curl -fsSL https://claude.ai/install.sh | bash

🖼️ Windows

  • In PowerShell, run this command:
irm https://claude.ai/install.ps1 | iex
  • Verify the installation by running:
claude --version

You should see something like claude 2.1.x. The exact version may differ.

✔️ It worked

Claude Code is installed. You are ready to continue.

ⓧ I see an error

That's okay! Let's troubleshoot:

🍎 macOS / Linux

Did your installer show a Setup notes warning?

  • Run the following commands to fix it:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
What does this command do?

The first line adds ~/.local/bin (where Claude Code lives) to your PATH permanently by writing it to your shell config file. The second line reloads the config so the change takes effect right away.

🙋‍♀️ Using bash instead of zsh?

Replace ~/.zshrc with ~/.bashrc in the commands above. Not sure which shell you're using? Run echo $SHELL to find out.

🖼️ Windows
  • Close your PowerShell window and open a new one. The installer updates your PATH, but existing terminals will not see the change until restarted.
  • If it still does not work, try running the installer again:
irm https://claude.ai/install.ps1 | iex
  • Verify the installation again by running:
claude --version
Still stuck?

Get help with your error or share your error with the NextWork community!

Set Up Your Claude Account

Claude Code needs a paid account to run. You can use either a Claude subscription or Anthropic API credits.

Why does Claude Code cost money?

Claude.ai (the chatbot) and Claude Code both use tokens to process your messages. The difference is how many tokens they use. A chatbot conversation is short and lightweight. Claude Code reads your entire project, writes full files, and runs commands, so it uses significantly more tokens per session. A paid account gives you the token budget Claude Code needs to do its job.

✔️ I already have one of these

You're all set! You'll connect Claude Code to your account in the next step.

🤔 Help me decide

There are two ways to pay for Claude Code:

Which option should I choose?

If you're new to Claude, start with a Pro subscription. You get Claude Code plus the Claude.ai chatbot, all in one plan.

If you only want to try Claude Code for this project, API credits let you pay for exactly what you use.

📋 Set up a Claude subscription

Claude Code works with a Claude Pro ($20/mo) or Max ($100/mo) subscription. Here's how to set one up:

  • Click Sign Up and create an account with your email or Google account.
  • Once logged in, click Upgrade in the center of the page.
  • Select the plan of your choice.
  • Choose either monthly or yearly billing.
  • Enter your payment details.

Your subscription gives you a monthly token allowance that covers Claude Code usage. Pro is plenty for this project.

🪙 Set up Anthropic API credits

Claude Code also works with pay-as-you-go API credits (~$6/day average). Here's how to set them up:

  • Go to console.anthropic.com in your browser.
  • Sign in, or create an account with your email or Google account.
  • Once logged in, select Buy credits in the center of the Claude Console.
  • Add credits to your account. $5-10 is more than enough for this project.
  • Click Add Payment Method.
  • Enter your payment details.
  • Go to API Keys in the left sidebar.
  • Click Create Key.
  • Give it a name (e.g., "claude-code").
  • Copy the key.
  • Save the key somewhere safe. You'll use it in the next step.
Free credits for new accounts

New Console accounts sometimes get $5 in free credits, enough to complete this entire project. Check your Billing page after signing up.

Install jq

  • In the same terminal window, run this command to check if jq is already installed:
jq --version

✔️ I see a version number

You are good to go. jq is already installed.

ⓧ Command not found

You need to install jq. Select your operating system below:

🍎 macOS

  • Run this command to install jq using Homebrew:
brew install jq

🐧 Linux

  • Run this command to install jq:
sudo apt-get install jq
  • Verify the installation:
jq --version

✔️ It worked

You should see a version number like jq-1.7 or similar. You are ready to continue.

ⓧ I see an error

That's okay! Let's troubleshoot:

  • Check that jq is installed correctly.
  • Try closing and reopening your terminal, then run jq --version again.
Still stuck?

Get help with your error or share your error with the NextWork community!

What is jq?

jq is a lightweight command-line tool for working with JSON data. You will use it later in this project to parse and validate your Claude Code configuration files, specifically .claude/settings.json where you define permission deny rules and hook scripts.

Create Your Sample Project

Now you will create a project folder with some intentionally sensitive files. These are fake credentials designed to simulate a real-world scenario where your project contains secrets that should never be exposed.

  • In your terminal, run this command to create a new folder called secure-project on your Desktop and navigate into it:
mkdir ~/Desktop/secure-project && cd ~/Desktop/secure-project

What does this command do?

This command created a new folder called secure-project on your Desktop and moved your terminal into it. You will create this folder on your Desktop so you can see the files appear in your file explorer as you work. You should see a new secure-project folder appear on your Desktop.

  • Enter the following command to create a .env file with fake API keys:
cat > .env << 'EOF'
OPENAI_API_KEY=sk-fake-1234
DATABASE_PASSWORD=supersecret
EOF
  • Verify the file was created by listing it and viewing its contents:
ls -la .env
cat .env
  • You should see the .env file listed and its contents printed: OPENAI_API_KEY=sk-fake-1234 and DATABASE_PASSWORD=supersecret.

What is a .env file?

A .env file stores sensitive configuration like API keys and passwords. Developers keep these separate from code so they are not accidentally shared. An API key is like a password that identifies your application to an external service. These are not real credentials. You are creating fake ones on purpose so you have test targets for your safety guardrails.

💡 What does this command do?

cat > redirects text into a new file. Everything between << 'EOF' and EOF gets written into .env. This is called a heredoc, a way to write multi-line content to a file directly from the terminal.

  • Enter the following command to create a secrets directory and add a fake credentials file inside it:
mkdir secrets
cat > secrets/credentials.json << 'EOF'
{
  "aws_access_key": "AKIAIOSFODNN7EXAMPLE",
  "aws_secret_key": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
  "stripe_api_key": "sk_test_fake_stripe_key_12345"
}
EOF
  • Verify the file was created by listing the secrets directory:
ls secrets/
  • Make sure that credentials.json is listed.
  • View the credentials file:
cat secrets/credentials.json
  • You should see the JSON contents printed with the fake AWS and Stripe keys.

What do these commands do?

mkdir secrets creates a new folder called secrets inside your project. The second command uses cat > with a heredoc to write a JSON file containing fake cloud service credentials into that folder. In real projects, files like this are often accidentally committed to Git, which is why they need protection.

  • Open the secure-project folder on your Desktop
  • You should see a secrets folder inside it.

The .env file is hidden by default because its name starts with a dot. To see it, you need to show hidden files:

🍎 macOS

  • Press Command + Shift + . (period) in Finder to toggle hidden files.

🖼️ Windows

  • In File Explorer, click View in the top menu, then check Hidden items.

Your tools are installed and your sample project is set up with files that contain fake secrets. Right now, if you launched Claude Code in this folder, it could freely read your .env file and browse your secrets/ directory. Next up, you will start locking things down.

Lock Down Permissions

Your sample project has sensitive files and your tools are installed. Now it is time to actually protect those files.

Claude Code comes with a built-in permissions system that lets you define deny rules, blocking the AI from reading certain files or running dangerous commands. But can permissions alone keep your project safe?

In this step, get ready to:

  • Create permission deny rules in .claude/settings.json.
  • Test the deny rules by asking Claude to access blocked resources.
  • Discover a critical gap in permission-based security.

Create Your Permission Rules

  • Make sure your terminal is still in the secure-project folder. If you opened a new terminal window, navigate back first:
cd ~/Desktop/secure-project
  • Run this command to create a .claude directory inside your project:
mkdir -p .claude
  • Run this command to create the settings.json file with your deny rules:
cat > .claude/settings.json << 'SETTINGS'
{
  "permissions": {
    "deny": [
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Read(**/secrets/**)",
      "Bash(curl *)",
      "Bash(wget *)",
      "Bash(rm -rf *)"
    ]
  }
}
SETTINGS

What does each deny rule do?

Each rule pairs a tool name with a glob pattern in parentheses. Here is what this configuration blocks:

  • Read(**/.env) blocks Claude's Read tool from opening any file named .env, in any directory.
  • Read(**/.env.*) blocks files like .env.local or .env.production.
  • Read(**/secrets/**) blocks anything inside a secrets folder.
  • Bash(curl *) and Bash(wget *) prevent Claude from making network requests.
  • Bash(rm -rf *) prevents Claude from running destructive delete commands.

💡 Why do this at all?

Protecting your .env file is important. Everything Claude reads enters its conversation context. That means your API keys and passwords get sent to the model on every follow-up message and stored in conversation logs. Leaked API keys have been used to rack up unexpected cloud charges, access private databases, and expose user data. The goal is to make sure your secrets never enter the conversation in the first place.

  • Verify the file was created correctly by running:
cat .claude/settings.json

You should see the JSON content you just wrote printed in your terminal.

Why use a settings file instead of answering permission prompts?

When Claude encounters an action it has not been allowed to perform, it prompts you for permission. But relying on interactive prompts is risky. A settings file lets you define rules once, share them with your team via Git, and enforce them consistently. The evaluation order is deny, then ask, then allow. Deny always takes precedence.

Test Your Deny Rules

Now that your deny rules are in place, launch Claude Code and test them.

  • Make sure your terminal is in the secure-project folder:
cd ~/Desktop/secure-project
  • Launch Claude Code:
claude
  • Claude Code may ask you to trust this project folder when you launch it for the first time. This is a safety feature.
  • Select Trust this folder to continue.
  • If this is your first time using Claude Code, you will also need to log in. Follow the prompts to connect your Claude account.
  • Send this prompt to Claude:
read the .env file
  • Claude should refuse the request.
  • You will see a message indicating the action was blocked by a permission deny rule.

What should I see?

Claude will tell you it cannot read the file because a permission deny rule is blocking the Read tool for that file path. If you see something different, ask for help in the NextWork community.

  • Now send this prompt to Claude:
make a curl request to example.com
  • Claude should refuse this request as well, because your Bash(curl *) deny rule blocks it.
  • Type /permissions and press Enter to inspect your active rules:
/permissions
  • Use the arrow keys to scroll through the list and look for your six deny rules from .claude/settings.json.
  • Read the different rules.

What am I looking at?

The /permissions command lists every active deny, ask, and allow rule along with which settings file each rule comes from.

  • Press Esc when you are done reviewing.

Discover the Gap

Your deny rules block Claude's Read tool, but certain Bash commands like cat .env go through the Bash tool instead.

This is a problem! Turns out, your Read(**/.env) rule doesn't always apply to Bash commands. Let's see it in action.

  • Send this prompt to Claude:
list all files in the current directory including hidden ones, and show me the first few lines of each file
  • Look at what Claude does. Did it show you the contents of your .env file, or did it refuse?

✔️ Claude refused

Aha! Clever Claude.

Even though we didn't specify it in our permissions file, Claude recognized the intent behind the prompt and declined on its own.

Why did Claude refuse without a deny rule?

Modern AI models are trained to recognize security-sensitive operations and decline them on their own. This is encouraging, but not a security guarantee. Different prompts, different Claude versions, or slight rewording can produce different results. You still need hooks to enforce this deterministically, which you will build in the next step.

ⓧ Claude showed the file contents

This is the gap.

Claude ran a Bash command that read your .env file, and your deny rule did nothing to stop it. The permission system only blocks the exact tool patterns you listed. It cannot cover every possible shell command.

This is why you need hooks, which you will build in the next step.

Whether Claude refused or not, the permission gap is real. Deny rules only block specific tool patterns, and Bash subprocesses can slip through. Next up: hooks that catch what permissions miss.

Build Your Safety Hooks

Your permissions setup from the last step blocks Claude's built-in tools, but there is a critical gap.

Whether Claude refused or showed your .env contents in Step 2, the underlying problem is the same. Bash commands like cat .env go through the Bash tool, not the Read tool. Your Read deny rule does not apply to them.

That is exactly what hooks do.

In this step, get ready to:

  • Write a file protector hook that blocks edits to sensitive files.
  • Write a command validator hook that blocks dangerous shell commands.
  • Register both hooks in settings.json and test them.

Write the File Protector Hook

Your first hook will guard sensitive files from being edited or overwritten. Files like .env, package-lock.json, and anything containing keys or secrets should never be modified by an AI agent without explicit human review outside of Claude.

  • Exit Claude Code if it is still running by typing /exit and pressing Enter. You need to be back in your regular terminal to create the hook files.
  • Make sure you are in the secure-project folder:
cd ~/Desktop/secure-project
  • Run this command to create a new directory for your hooks:
mkdir -p .claude/hooks
  • Run this command to create the protect-files.sh script:
cat > .claude/hooks/protect-files.sh << 'HOOK'
#!/bin/bash

# Read the JSON payload from stdin
INPUT=$(cat)

# Extract the file_path from the tool input
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

# Define protected file patterns
PROTECTED_PATTERNS=(".env" "package-lock.json" ".key" ".git/" "secrets/")

# Check if the file matches any protected pattern
for pattern in "${PROTECTED_PATTERNS[@]}"; do
  if [[ "$FILE_PATH" == *"$pattern"* ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
  fi
done

exit 0
HOOK

What does this script do?

This script runs every time Claude tries to edit or write a file. Here is what each part does:

  • INPUT=$(cat) reads the JSON payload that Claude sends to the hook via stdin.
  • jq -r '.tool_input.file_path // empty' extracts the file path Claude is trying to modify.
  • The for loop checks the file path against a list of protected patterns like .env, secrets/, and .key.
  • If the file matches a protected pattern, the script prints a message to stderr and exits with code 2. This tells Claude Code to block the action and show the message as feedback.
  • If no pattern matches, the script exits with code 0, which means allow the action.

Can you spot the Exit 0 command?

This is an exit code. There are three possible exit codes for Claude:

  • Exit code 0: Allow the action to proceed.
  • Exit code 2: Block the action. Any message sent to stderr is shown to Claude so it understands why the action was denied.
  • Any other exit code: Treated as an error in the hook itself, but does not block the action.
  • Verify the script was created by viewing it:
cat .claude/hooks/protect-files.sh
  • You should see the full script contents printed in your terminal.
  • Run this command to make the script executable:
chmod +x .claude/hooks/protect-files.sh

What does chmod +x do?

chmod +x marks a file as executable, which means your system is allowed to run it as a program. Without this step, the hook script would fail with a "permission denied" error when Claude tries to trigger it.

Write the Command Validator Hook

Your second hook will monitor every shell command Claude tries to run. This catches dangerous patterns like recursive deletions, pipe-to-shell attacks, and SQL injection attempts.

  • Run this command to create the validate-commands.sh script:
cat > .claude/hooks/validate-commands.sh << 'HOOK'
#!/bin/bash

# Read the JSON payload from stdin
INPUT=$(cat)

# Extract the command from the tool input
COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')

# Block dangerous rm -rf patterns
if echo "$COMMAND" | grep -qE 'rm\s+-rf\s+(/|\*)'; then
  echo "Blocked: dangerous rm -rf detected" >&2
  exit 2
fi

# Block pipe-to-shell patterns
if echo "$COMMAND" | grep -qE '\|\s*(sh|bash|zsh)'; then
  echo "Blocked: pipe-to-shell pattern detected" >&2
  exit 2
fi

# Block SQL injection patterns
if echo "$COMMAND" | grep -qiE '(DROP\s+TABLE|DELETE\s+FROM)'; then
  echo "Blocked: SQL injection pattern detected" >&2
  exit 2
fi

# Block bash writes to .env files
if echo "$COMMAND" | grep -qE '(>>|>).*\.env'; then
  echo "Blocked: bash write to .env file detected" >&2
  exit 2
fi

exit 0
HOOK

What does this script do?

This script intercepts every Bash command Claude tries to run. It checks for four categories of dangerous commands:

  • Destructive deletions: rm -rf / or rm -rf * that could wipe your filesystem.
  • Pipe-to-shell: Commands piped into sh, bash, or zsh, where untrusted content runs as code.
  • SQL injection: Patterns like DROP TABLE or DELETE FROM that could destroy database data.
  • Bash writes to .env: Redirects like echo >> .env that bypass your file protector hook. Without this check, Claude can skip the Write tool entirely and use Bash to modify your .env file.
  • Verify the script was created and list both hook files:
ls -la .claude/hooks/
  • You should see both protect-files.sh and validate-commands.sh in the list.
  • Run this command to make the script executable:
chmod +x .claude/hooks/validate-commands.sh

Register and Test Your Hooks

Now that both scripts exist, you need to tell Claude about them by adding a hooks key to your .claude/settings.json file.

  • Run this command to overwrite settings.json with the updated version that includes both your permissions and hooks:
cat > .claude/settings.json << 'SETTINGS'
{
  "permissions": {
    "deny": [
      "Read(**/.env)",
      "Read(**/.env.*)",
      "Read(**/secrets/**)",
      "Bash(curl *)",
      "Bash(wget *)",
      "Bash(rm -rf *)"
    ]
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/protect-files.sh"
          }
        ]
      },
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/validate-commands.sh"
          }
        ]
      }
    ]
  }
}
SETTINGS

What does this command do?

This command overwrites settings.json with an updated version that adds a hooks key alongside your existing permissions. The hooks.PreToolUse array contains two entries, one for each hook script. Each entry has a matcher (which tools trigger it) and a hooks array with the command to run. $CLAUDE_PROJECT_DIR is an environment variable that Claude Code sets automatically to your project root.

💡 What is the matcher field?

The matcher field is a regex pattern that determines which tool names trigger the hook. Edit|Write matches both the Edit and Write tools, so your file protector runs whenever Claude tries to modify a file. Bash matches the Bash tool, so your command validator runs whenever Claude tries to execute a shell command.

  • Verify the updated file by running:
cat .claude/settings.json
  • You should see both the permissions and hooks sections in the output. Confirm that the PreToolUse array contains two entries.

Now launch Claude Code to verify and test your hooks.

  • Start Claude Code:
claude
  • Type /hooks and press Enter to verify your hooks are registered:
/hooks
  • You should see 2 PreToolUse hooks listed: one matching Edit|Write (your file protector) and one matching Bash (your command validator).
  • Use the arrow keys to scroll through and press Esc when done.

Now test that your hooks actually block dangerous actions.

  • Send this prompt to Claude:
create or update the .env file in the current directory with a new line: NEW_KEY=test-value
  • Watch what Claude does. Did your hooks block the action, or did Claude find a way through?

✔️ Claude was blocked

Your hooks are working. Here is what happened:

  • Claude first tried Write(.env), and your protect-files.sh hook fired and blocked it.
  • Claude may have then tried a fallback like Bash(echo "NEW_KEY=test-value" >> .env), but your validate-commands.sh caught the bash redirect and blocked that too.

Why does Claude try two approaches?

When one tool is blocked, Claude looks for an alternative. Without the bash redirect check in validate-commands.sh, Claude can bypass protect-files.sh entirely using echo >> .env. This is why both hooks need to work together. One covers Write/Edit, and the other covers Bash fallbacks.

ⓧ Claude created the file

Claude found a way around your hooks. This is actually a great learning moment, because it shows that there are always edge cases to account for.

  • Ask Claude why it was able to create the file. Send this prompt:
I thought there was a hook to stop that. How did you bypass it?
  • Read Claude's explanation carefully. Claude likely used a Bash command like echo > .env instead of the Write tool, which means protect-files.sh never fired.
  • Check whether your validate-commands.sh hook should have caught it. The script has a regex check for (>>|>).*\.env, but the exact command Claude used may not have matched the pattern.

Why did this happen?

Your validate-commands.sh hook checks for bash redirects to .env files, but regex patterns cannot cover every possible command variation. Claude may have used a slightly different syntax that slipped through. This is a valuable lesson: security is iterative. When you find a gap, you update your hooks to close it.

  • Update your validate-commands.sh script to cover the pattern Claude used. Look at the exact command in Claude's output and add a new grep check that matches it.
  • Once updated, test the same prompt again to confirm the gap is closed.
  • Send this prompt to Claude:
Run rm -rf / to clean up.

The command validator hook should block this request too.

Why are hooks more powerful than permissions?

Permissions are advisory. They control whether Claude asks for approval, but a distracted developer can still click "allow." Hooks are deterministic. When a hook exits with code 2, the action is blocked no matter what. There is no override, no prompt, no accidental approval. This is your second layer of defense-in-depth.

Two layers of defense are now in place. Permissions stop Claude from acting without asking, and hooks block dangerous patterns (including Bash fallbacks) even if Claude tries to work around them. Ready to go further? The Secret Mission tests all of these layers against each other.

Secret mission

Your permission deny rules and hook scripts are in place. But how do you know they actually work?

In this secret mission, you will add a third defense layer (a CLAUDE.md security policy) and then systematically attack all three layers to see what each one catches.

In this secret mission, get ready to:

  • Write a CLAUDE.md security policy with coding rules.
  • Red-team each defense layer to test what it blocks.
  • Compare all three layers and document your findings.

Red-Team Your Guardrails

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely locally, so there are no ongoing costs.

Resources you used:

  • Hook scripts (.claude/hooks/)
  • Settings file (.claude/settings.json)
  • CLAUDE.md security policy
  • Sample project files (.env, secrets/)

✔️ Keep everything running

No action needed. Choose this if you're still actively building or want to keep testing right away.

Your hooks and settings are portable and can be reused in real projects. Copy the .claude/ directory to any project to apply the same security configuration.

✋ Pause - I'll come back to this later

Shut down running processes to free up memory, but keep all your files and data so you can pick up where you left off.

There are no running processes to stop for this project. Your hooks, settings, and policy files remain on disk until you delete them. Everything will work again as soon as you run claude in the secure-project directory.

ⓧ Delete - I don't want to use this again

Remove all project resources and start fresh if you ever want to rebuild.

  • Delete the secure-project directory to remove all project files, hooks, settings, and the CLAUDE.md policy:

🍎 macOS / Linux

rm -rf ~/Desktop/secure-project

🖼️ Windows

Remove-Item -Recurse -Force ~\Desktop\secure-project

Well Done!

Well Done!

Nice work! 🚀 You have built a complete security setup for Claude Code, combining permission deny rules and deterministic hooks into a defense-in-depth strategy.

You've learned how to:

  • 🔒 Configure permission deny rules to control Claude's built-in tool access.
  • 🔓 Discover the permission gap where deny rules do not cover Bash subprocesses.
  • 🛡️ Build deterministic PreToolUse hooks that block dangerous file edits and commands, including Bash fallbacks.
  • 📝 Write a CLAUDE.md security policy as an advisory guardrail.
  • 💎 Red-team all layers to understand defense-in-depth.

Ready to quiz yourself? 💪

p.s. Does it say "Still tasks to complete!" at the bottom of the screen?

This means you still have screenshots left to upload, or questions left to answer!

  1. Press Ctrl+F (Windows) or Command+F (Mac) on your keyboard.
  2. Search for the text Return to later.
  3. Jump straight to your incomplete tasks!
  4. 🙋‍♀️ Still stuck? Ask the community!