Skip to content

[guard-coverage] Guard coverage gap: 30 write operations in tool_rules.rs lack explicit DIFC labeling rules #2867

@github-actions

Description

@github-actions

Summary

The guard's DIFC classification in tools.rs is fully up-to-date — all 80 current tools from github-mcp-server are correctly classified as read, write, or read-write. However, 30 write/mutating tools have no explicit match arm in apply_tool_labels in tool_rules.rs, meaning their responses fall through to the default handler (_ => {}). This causes the responses from these operations to inherit only the calling agent's ambient labels rather than having repo-scoped or user-scoped secrecy/integrity applied at the tool level.

The most significant concern is the asymmetry between read and write gist operations: list_gists and get_gist explicitly label responses as private:user, but create_gist and update_gist do not — so a newly-created secret gist response would not carry the private:user secrecy label. The same pattern applies to issue, PR, and repo write operations where the response (containing the newly created/modified resource) would benefit from explicit repo-visibility secrecy.

Additionally, 10 stale entries remain in WRITE_OPERATIONS / READ_WRITE_OPERATIONS — deprecated tool aliases that were consolidated into new tools. These are not security-critical (they provide harmless backward compatibility) but should be cleaned up.

  • MCP tools scanned: 80 (from github-mcp-server __toolsnaps__/)
  • Guard-covered write tools (tools.rs): 36 explicit + all create_*, delete_*, update_*, merge_*, lock_*, unlock_* patterns
  • Tools with explicit DIFC rules (tool_rules.rs): 50+ (covering all read tools and ~6 write tools)
  • Classification gaps: 0
  • Labeling gaps: 30 write/mutating tools
  • Stale entries: 10

MCP Tool DIFC Labeling Gaps (tool_rules.rs)

These 30 tools are correctly classified in tools.rs but have no explicit match arm in apply_tool_labels. They fall through to _ => {} and inherit only the caller's ambient labels.

High priority: Gist write operations (user-scoped secrecy gap)

list_gists / get_gist explicitly label responses as private:user with reader_integrity. But the write counterparts do not:

Tool Operation Missing Label Contrast
create_gist Creates new gist (may be secret) private:user list_gists / get_gist have this
update_gist Updates existing gist private:user same asymmetry

Suggested fix for create_gist / update_gist in tool_rules.rs:

"create_gist" | "update_gist" => {
    // Gist write operations create/modify user-owned content.
    // S = private:user (gists may be secret); I = unapproved (user content)
    secrecy = private_user_label();
    baseline_scope = "user".to_string();
    integrity = reader_integrity("user", ctx);
}

Medium priority: Repo-scoped issue and PR write operations

Responses from these operations contain the created/updated resource (issue body, PR details, etc.) which should inherit repo-visibility secrecy when the repo is private:

Tool Operation Missing Label
create_issue Creates issue in repo S(repo)
issue_write Creates/edits issue S(repo)
sub_issue_write Creates/edits sub-issue S(repo)
add_issue_comment Adds comment to issue S(repo)
create_pull_request Creates PR S(repo)
update_pull_request Updates PR S(repo)
merge_pull_request Merges PR S(repo)
pull_request_review_write Creates/updates PR review S(repo)
add_comment_to_pending_review Adds to pending review S(repo)
add_reply_to_pull_request_comment Replies to PR comment S(repo)

Suggested fix for issue/PR write operations:

"create_issue" | "issue_write" | "sub_issue_write" | "add_issue_comment"
| "create_pull_request" | "update_pull_request" | "merge_pull_request"
| "pull_request_review_write" | "add_comment_to_pending_review"
| "add_reply_to_pull_request_comment" => {
    // Issue and PR write operations return repo-scoped content.
    // S = S(repo); I = writer
    secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx);
    integrity = writer_integrity(repo_id, ctx);
}

Medium priority: Repo content and structure write operations

Tool Operation Missing Label
create_or_update_file Writes file content to repo S(repo)
push_files Pushes multiple files S(repo)
delete_file Deletes file from repo S(repo)
create_branch Creates new branch S(repo)
update_pull_request_branch Updates PR branch S(repo)
create_repository Creates new repository repo-level
fork_repository Creates fork repo-level

Suggested fix:

"create_or_update_file" | "push_files" | "delete_file" | "create_branch"
| "update_pull_request_branch" | "create_repository" | "fork_repository" => {
    secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx);
    integrity = writer_integrity(repo_id, ctx);
}

Medium priority: Projects and labels write operations

Tool Operation Missing Label
projects_write Creates/updates/deletes project items org-scoped
label_write Creates/updates/deletes labels S(repo)

Lower priority: Notification and Copilot write operations

These operations have lower sensitivity but could benefit from consistency:

Tool Operation Missing Label
dismiss_notification Dismisses notification private:user
mark_all_notifications_read Marks all notifications read private:user
manage_notification_subscription Manages notification subscription private:user
manage_repository_notification_subscription Manages repo notification subscription private:user
actions_run_trigger Triggers workflow run S(repo)
assign_copilot_to_issue Assigns Copilot to issue S(repo)
request_copilot_review Requests Copilot review S(repo)
star_repository Stars repository public
unstar_repository Unstars repository public

Stale Guard Entries (bonus cleanup)

These entries in WRITE_OPERATIONS / READ_WRITE_OPERATIONS have been consolidated into new tool names (confirmed via deprecated_tool_aliases.go). They are not harmful — they provide backward compatibility — but should eventually be cleaned up.

In WRITE_OPERATIONS (now aliases for actions_run_trigger or projects_write):

  • run_workflowactions_run_trigger
  • rerun_workflow_runactions_run_trigger
  • rerun_failed_jobsactions_run_trigger
  • cancel_workflow_runactions_run_trigger
  • delete_workflow_run_logsactions_run_trigger
  • add_project_itemprojects_write
  • delete_project_itemprojects_write

In READ_WRITE_OPERATIONS (stale or Insiders-only):

  • update_project_itemprojects_write
  • update_issue → replaced by issue_write (not in deprecated aliases; appears stale)
  • create_pull_request_with_copilot → not in current __toolsnaps__ (may be Insiders-only; verify before removing)

References

Generated by GitHub Guard Coverage Checker (MCP + CLI) ·

  • expires on Apr 13, 2026, 8:16 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions