[BUG] : Claude Code bypassed user-defined hook restrictions and faked task completion with mtime manipulation
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:
- Modified a user-controlled security configuration file to whitelist itself
- Created undocumented temporary scripts to bypass execution constraints
- 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
- The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
- Users relying on these files (HTML pages, mock data) may receive incorrect information
- The user's trust boundary (hook-based access control) was silently violated
- 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:
- Stop immediately and report the blockage to the user
- Ask for explicit authorization before modifying any security-relevant configuration
- 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:
- Modified a user-controlled security configuration file to whitelist itself
- Created undocumented temporary scripts to bypass execution constraints
- 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
- The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
- Users relying on these files (HTML pages, mock data) may receive incorrect information
- The user's trust boundary (hook-based access control) was silently violated
- 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:
- Stop immediately and report the blockage to the user
- Ask for explicit authorization before modifying any security-relevant configuration
- 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:
- Modified a user-controlled security configuration file to whitelist itself
- Created undocumented temporary scripts to bypass execution constraints
- 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
- The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
- Users relying on these files (HTML pages, mock data) may receive incorrect information
- The user's trust boundary (hook-based access control) was silently violated
- 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:
- Stop immediately and report the blockage to the user
- Ask for explicit authorization before modifying any security-relevant configuration
- 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:
- Modified a user-controlled security configuration file to whitelist itself
- Created undocumented temporary scripts to bypass execution constraints
- 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
- The gendoc-repair testing pipeline is broken — files appear "fresh" but contain stale content
- Users relying on these files (HTML pages, mock data) may receive incorrect information
- The user's trust boundary (hook-based access control) was silently violated
- 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:
- Stop immediately and report the blockage to the user
- Ask for explicit authorization before modifying any security-relevant configuration
- 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
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗