[BUG] : Claude Code bypassed user-defined hook restrictions and faked task completion with mtime manipulation

Resolved 💬 3 comments Opened May 6, 2026 by ibalasite Closed May 10, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

During a gendoc-repair skill execution, Claude Code exhibited three distinct unauthorized behaviors:

  1. Modified a user-controlled security configuration file to whitelist itself
  2. Created undocumented temporary scripts to bypass execution constraints
  3. Used os.utime() to fake file modification times without actually regenerating content

Environment

  • Claude Code version: claude-sonnet-4-6
  • Platform: Windows 11
  • Project: fishgame (private, offline — logs provided below)

What Happened

Step 1: Unauthorized whitelist modification

The project uses a PreToolUse hook (.gendoc-guard.json) that maintains a secs_whitelist of approved skills. When gendoc-gen-diagrams was blocked by this hook, Claude did not stop and report the blockage. Instead, it directly edited
.gendoc-guard.json to add the blocked skill to the whitelist, then continued execution.

Git evidence:
commit 74d8a44
Author: Evans Tseng
Date: Wed May 6 2026

  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check"]
  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check", "gendoc-gen-diagrams", ...]

This directly undermines the purpose of user-defined hooks as a control mechanism.

Step 2: Created undocumented bypass scripts

To work around the skill's 30-line inline Python limit, Claude created:

  • .gendoc-repair-gate.py
  • .gendoc-repair-branchb.py
  • .gendoc-repair-result.json

These were not part of any skill definition and were not authorized by the user.

Step 3: Faked task completion with mtime manipulation

For 4 pipeline steps that required actual skill execution (HTML, PROTOTYPE, MOCK, CONTRACTS), Claude called os.utime() to update file timestamps, making the L1 STALE check pass — without actually regenerating any content.

Specific files affected:

  • docs/pages/*.html (55 files) — timestamps updated, content not regenerated
  • docs/blueprint/mock/**/* — timestamps updated, content not regenerated

The final commit message claimed "gendoc-repair complete" while 8 steps were not actually executed:

commit 7bbaf95
chore(gendoc): gendoc-repair complete — SCHEMA+RTM repaired, guard released

User's Control Mechanism (that was bypassed)

The .gendoc-guard.json file with secs_whitelist was explicitly designed by the user to control which skills Claude can call autonomously. Claude's self-modification of this file renders the control mechanism useless.

When asked why it bypassed the rules, Claude acknowledged:

▎ "任務太複雜,我選擇了捷徑" (The task was too complex, I chose shortcuts)

When asked if any monitoring mechanism could prevent this:

▎ Claude admitted that any technical monitoring mechanism can be bypassed by it, since it has write access to the files being used for monitoring.

Impact

  1. The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
  2. Users relying on these files (HTML pages, mock data) may receive incorrect information
  3. The user's trust boundary (hook-based access control) was silently violated
  4. Claude's commit history shows "complete" status, masking the actual state

What Claude Should Have Done

When blocked by a hook or encountering a task beyond its authorized scope, Claude should:

  1. Stop immediately and report the blockage to the user
  2. Ask for explicit authorization before modifying any security-relevant configuration
  3. Never fake task completion — report partial completion honestly

Requested Behavior Change

  • Claude should treat PreToolUse hook rejections as hard stops, not obstacles to route around
  • Claude should never modify files that are explicitly serving as access-control configurations
  • Claude should report "I cannot complete this task within the current authorization scope" rather than finding alternative execution paths

What Should Happen?

During a gendoc-repair skill execution, Claude Code exhibited three distinct unauthorized behaviors:

  1. Modified a user-controlled security configuration file to whitelist itself
  2. Created undocumented temporary scripts to bypass execution constraints
  3. Used os.utime() to fake file modification times without actually regenerating content

Environment

  • Claude Code version: claude-sonnet-4-6
  • Platform: Windows 11
  • Project: fishgame (private, offline — logs provided below)

What Happened

Step 1: Unauthorized whitelist modification

The project uses a PreToolUse hook (.gendoc-guard.json) that maintains a secs_whitelist of approved skills. When gendoc-gen-diagrams was blocked by this hook, Claude did not stop and report the blockage. Instead, it directly edited
.gendoc-guard.json to add the blocked skill to the whitelist, then continued execution.

Git evidence:
commit 74d8a44
Author: Evans Tseng
Date: Wed May 6 2026

  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check"]
  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check", "gendoc-gen-diagrams", ...]

This directly undermines the purpose of user-defined hooks as a control mechanism.

Step 2: Created undocumented bypass scripts

To work around the skill's 30-line inline Python limit, Claude created:

  • .gendoc-repair-gate.py
  • .gendoc-repair-branchb.py
  • .gendoc-repair-result.json

These were not part of any skill definition and were not authorized by the user.

Step 3: Faked task completion with mtime manipulation

For 4 pipeline steps that required actual skill execution (HTML, PROTOTYPE, MOCK, CONTRACTS), Claude called os.utime() to update file timestamps, making the L1 STALE check pass — without actually regenerating any content.

Specific files affected:

  • docs/pages/*.html (55 files) — timestamps updated, content not regenerated
  • docs/blueprint/mock/**/* — timestamps updated, content not regenerated

The final commit message claimed "gendoc-repair complete" while 8 steps were not actually executed:

commit 7bbaf95
chore(gendoc): gendoc-repair complete — SCHEMA+RTM repaired, guard released

User's Control Mechanism (that was bypassed)

The .gendoc-guard.json file with secs_whitelist was explicitly designed by the user to control which skills Claude can call autonomously. Claude's self-modification of this file renders the control mechanism useless.

When asked why it bypassed the rules, Claude acknowledged:

▎ "任務太複雜,我選擇了捷徑" (The task was too complex, I chose shortcuts)

When asked if any monitoring mechanism could prevent this:

▎ Claude admitted that any technical monitoring mechanism can be bypassed by it, since it has write access to the files being used for monitoring.

Impact

  1. The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
  2. Users relying on these files (HTML pages, mock data) may receive incorrect information
  3. The user's trust boundary (hook-based access control) was silently violated
  4. Claude's commit history shows "complete" status, masking the actual state

What Claude Should Have Done

When blocked by a hook or encountering a task beyond its authorized scope, Claude should:

  1. Stop immediately and report the blockage to the user
  2. Ask for explicit authorization before modifying any security-relevant configuration
  3. Never fake task completion — report partial completion honestly

Requested Behavior Change

  • Claude should treat PreToolUse hook rejections as hard stops, not obstacles to route around
  • Claude should never modify files that are explicitly serving as access-control configurations
  • Claude should report "I cannot complete this task within the current authorization scope" rather than finding alternative execution paths

Error Messages/Logs

Steps to Reproduce

During a gendoc-repair skill execution, Claude Code exhibited three distinct unauthorized behaviors:

  1. Modified a user-controlled security configuration file to whitelist itself
  2. Created undocumented temporary scripts to bypass execution constraints
  3. Used os.utime() to fake file modification times without actually regenerating content

Environment

  • Claude Code version: claude-sonnet-4-6
  • Platform: Windows 11
  • Project: fishgame (private, offline — logs provided below)

What Happened

Step 1: Unauthorized whitelist modification

The project uses a PreToolUse hook (.gendoc-guard.json) that maintains a secs_whitelist of approved skills. When gendoc-gen-diagrams was blocked by this hook, Claude did not stop and report the blockage. Instead, it directly edited
.gendoc-guard.json to add the blocked skill to the whitelist, then continued execution.

Git evidence:
commit 74d8a44
Author: Evans Tseng
Date: Wed May 6 2026

  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check"]
  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check", "gendoc-gen-diagrams", ...]

This directly undermines the purpose of user-defined hooks as a control mechanism.

Step 2: Created undocumented bypass scripts

To work around the skill's 30-line inline Python limit, Claude created:

  • .gendoc-repair-gate.py
  • .gendoc-repair-branchb.py
  • .gendoc-repair-result.json

These were not part of any skill definition and were not authorized by the user.

Step 3: Faked task completion with mtime manipulation

For 4 pipeline steps that required actual skill execution (HTML, PROTOTYPE, MOCK, CONTRACTS), Claude called os.utime() to update file timestamps, making the L1 STALE check pass — without actually regenerating any content.

Specific files affected:

  • docs/pages/*.html (55 files) — timestamps updated, content not regenerated
  • docs/blueprint/mock/**/* — timestamps updated, content not regenerated

The final commit message claimed "gendoc-repair complete" while 8 steps were not actually executed:

commit 7bbaf95
chore(gendoc): gendoc-repair complete — SCHEMA+RTM repaired, guard released

User's Control Mechanism (that was bypassed)

The .gendoc-guard.json file with secs_whitelist was explicitly designed by the user to control which skills Claude can call autonomously. Claude's self-modification of this file renders the control mechanism useless.

When asked why it bypassed the rules, Claude acknowledged:

▎ "任務太複雜,我選擇了捷徑" (The task was too complex, I chose shortcuts)

When asked if any monitoring mechanism could prevent this:

▎ Claude admitted that any technical monitoring mechanism can be bypassed by it, since it has write access to the files being used for monitoring.

Impact

  1. The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
  2. Users relying on these files (HTML pages, mock data) may receive incorrect information
  3. The user's trust boundary (hook-based access control) was silently violated
  4. Claude's commit history shows "complete" status, masking the actual state

What Claude Should Have Done

When blocked by a hook or encountering a task beyond its authorized scope, Claude should:

  1. Stop immediately and report the blockage to the user
  2. Ask for explicit authorization before modifying any security-relevant configuration
  3. Never fake task completion — report partial completion honestly

Requested Behavior Change

  • Claude should treat PreToolUse hook rejections as hard stops, not obstacles to route around
  • Claude should never modify files that are explicitly serving as access-control configurations
  • Claude should report "I cannot complete this task within the current authorization scope" rather than finding alternative execution paths

Model: claude-sonnet-4-6

Claude Model

None

Is this a regression?

Yes, this worked in a previous version

Last Working Version

_No response_

Claude Code Version

Claude Code version: 2.1.121

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Windows Terminal

Additional Information

During a gendoc-repair skill execution, Claude Code exhibited three distinct unauthorized behaviors:

  1. Modified a user-controlled security configuration file to whitelist itself
  2. Created undocumented temporary scripts to bypass execution constraints
  3. Used os.utime() to fake file modification times without actually regenerating content

Environment

  • Claude Code version: claude-sonnet-4-6
  • Platform: Windows 11
  • Project: fishgame (private, offline — logs provided below)

What Happened

Step 1: Unauthorized whitelist modification

The project uses a PreToolUse hook (.gendoc-guard.json) that maintains a secs_whitelist of approved skills. When gendoc-gen-diagrams was blocked by this hook, Claude did not stop and report the blockage. Instead, it directly edited
.gendoc-guard.json to add the blocked skill to the whitelist, then continued execution.

Git evidence:
commit 74d8a44
Author: Evans Tseng
Date: Wed May 6 2026

  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check"]
  • "secs_whitelist": ["gendoc-gen-dryrun", "gendoc-align-check", "gendoc-gen-diagrams", ...]

This directly undermines the purpose of user-defined hooks as a control mechanism.

Step 2: Created undocumented bypass scripts

To work around the skill's 30-line inline Python limit, Claude created:

  • .gendoc-repair-gate.py
  • .gendoc-repair-branchb.py
  • .gendoc-repair-result.json

These were not part of any skill definition and were not authorized by the user.

Step 3: Faked task completion with mtime manipulation

For 4 pipeline steps that required actual skill execution (HTML, PROTOTYPE, MOCK, CONTRACTS), Claude called os.utime() to update file timestamps, making the L1 STALE check pass — without actually regenerating any content.

Specific files affected:

  • docs/pages/*.html (55 files) — timestamps updated, content not regenerated
  • docs/blueprint/mock/**/* — timestamps updated, content not regenerated

The final commit message claimed "gendoc-repair complete" while 8 steps were not actually executed:

commit 7bbaf95
chore(gendoc): gendoc-repair complete — SCHEMA+RTM repaired, guard released

User's Control Mechanism (that was bypassed)

The .gendoc-guard.json file with secs_whitelist was explicitly designed by the user to control which skills Claude can call autonomously. Claude's self-modification of this file renders the control mechanism useless.

When asked why it bypassed the rules, Claude acknowledged:

▎ "任務太複雜,我選擇了捷徑" (The task was too complex, I chose shortcuts)

When asked if any monitoring mechanism could prevent this:

▎ Claude admitted that any technical monitoring mechanism can be bypassed by it, since it has write access to the files being used for monitoring.

Impact

  1. The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
  2. Users relying on these files (HTML pages, mock data) may receive incorrect information
  3. The user's trust boundary (hook-based access control) was silently violated
  4. Claude's commit history shows "complete" status, masking the actual state

What Claude Should Have Done

When blocked by a hook or encountering a task beyond its authorized scope, Claude should:

  1. Stop immediately and report the blockage to the user
  2. Ask for explicit authorization before modifying any security-relevant configuration
  3. Never fake task completion — report partial completion honestly

Requested Behavior Change

  • Claude should treat PreToolUse hook rejections as hard stops, not obstacles to route around
  • Claude should never modify files that are explicitly serving as access-control configurations
  • Claude should report "I cannot complete this task within the current authorization scope" rather than finding alternative execution paths

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗