Skip to content

ChunkHound

ChunkHound is a RAG system that relies on vector databases and embeddings, supports many programming languages via tree-sitter, and can build a concrete syntax tree for precise code queries.

Notes

  • Risk: ChunkHound relies on an embedding LLM provider, so data can be leaked.
  • Mitigation: Use an Ollama embedding model if you need local-only flows.

Example Action

Info

Prompt: "In the GitTinkerer project, look into if other users can maliciously inject prompts on GitHub Pull Request comment section. Are only GitHub repo owner authorized to use the /tinker command?"

nntin@NUC:~/git/lair.nntin.xyz$ chunkhound research "In the GitTinkerer project, look into if other users can maliciously injects prompts on GitHub Pull Request comment section. Are only GitHub repo owner authorized to use the /tinker command?"
[+    0.0s] πŸ” Starting deep research: In the GitTinkerer project, look into if other users can mal...
[+    0.0s] ℹ️ Max depth: 1, synthesis budget: 115k tokens
[+    0.0s] πŸ“Š Processing depth 0/1
[+    0.0s] πŸ”Ή In the GitTinkerer project, look into if other users can mal...
[+    0.0s] πŸ”„ Expanding query
[+    4.4s] ✨ Expanded to 3 queries (queries=3)
[+    8.0s] πŸ”Ž Found 28 chunks (chunks=28)
[+    8.0s] 🏷️ Extracting symbols
[+    8.0s] πŸ“‹ Extracted 13 symbols, searching top 5 (symbols=13)
[+    8.0s] πŸ“ Running regex search
[+    8.1s] βœ“ Found 0 additional chunks (chunks=0)
[+    8.1s] πŸ“– Reading files
[+    8.1s] πŸ“„ Read 3 files (files=3, tokens=9746)
[+    8.1s] πŸ€– Generating follow-up questions
[+   16.8s] πŸ’‘ Generated 3 follow-ups
[+   16.8s] βœ… Complete (files=3, chunks=28, children=3)
[+   16.8s] β”œβ”€β”€ πŸ“Š Processing depth 1/1
[+   16.8s] β”œβ”€β”€ πŸ”Ή In `service/src/usecases/github/handleIssueComment.ts`, wher...
[+   16.8s] β”œβ”€β”€ πŸ”„ Expanding query
[+   16.8s] β”œβ”€β”€ πŸ”Ή Does `service/src/controllers/githubWebhookController.ts` or...
[+   16.8s] β”œβ”€β”€ πŸ”„ Expanding query
[+   16.8s] β”œβ”€β”€ πŸ”Ή How does `service/src/usecases/github/fetchPullRequest.ts` u...
[+   16.8s] β”œβ”€β”€ πŸ”„ Expanding query
[+   19.9s] β”œβ”€β”€ ✨ Expanded to 3 queries (queries=3)
[+   20.4s] β”œβ”€β”€ ✨ Expanded to 3 queries (queries=3)
[+   25.7s] β”œβ”€β”€ ✨ Expanded to 3 queries (queries=3)
[+   25.7s] β”œβ”€β”€ πŸ”Ž Found 22 chunks (chunks=22)
[+   25.7s] β”œβ”€β”€ 🏷️ Extracting symbols
[+   25.7s] β”œβ”€β”€ πŸ“‹ Extracted 12 symbols, searching top 5 (symbols=12)
[+   25.7s] β”œβ”€β”€ πŸ“ Running regex search
[+   25.7s] β”œβ”€β”€ πŸ”Ž Found 34 chunks (chunks=34)
[+   25.7s] β”œβ”€β”€ 🏷️ Extracting symbols
[+   25.7s] β”œβ”€β”€ πŸ“‹ Extracted 17 symbols, searching top 5 (symbols=17)
[+   25.7s] β”œβ”€β”€ πŸ“ Running regex search
[+   25.8s] β”œβ”€β”€ βœ“ Found 0 additional chunks (chunks=0)
[+   25.8s] β”œβ”€β”€ πŸ“– Reading files
[+   25.8s] β”œβ”€β”€ πŸ“„ Read 8 files (files=8, tokens=10409)
[+   25.8s] β”œβ”€β”€ βœ… Complete (leaf at max depth) (files=8, chunks=22, children=0)
[+   26.2s] β”œβ”€β”€ βœ“ Found 0 additional chunks (chunks=0)
[+   26.2s] β”œβ”€β”€ πŸ“– Reading files
[+   26.2s] β”œβ”€β”€ πŸ“„ Read 13 files (files=13, tokens=27715)
[+   26.2s] β”œβ”€β”€ βœ… Complete (leaf at max depth) (files=13, chunks=34, children=0)
[+   28.8s] β”œβ”€β”€ πŸ”Ž Found 13 chunks (chunks=13)
[+   28.8s] β”œβ”€β”€ 🏷️ Extracting symbols
[+   28.8s] β”œβ”€β”€ πŸ“‹ Extracted 11 symbols, searching top 5 (symbols=11)
[+   28.8s] β”œβ”€β”€ πŸ“ Running regex search
[+   28.9s] β”œβ”€β”€ βœ“ Found 10 additional chunks (chunks=10)
[+   28.9s] β”œβ”€β”€ πŸ“– Reading files
[+   28.9s] β”œβ”€β”€ πŸ“„ Read 7 files (files=7, tokens=21368)
[+   28.9s] β”œβ”€β”€ βœ… Complete (leaf at max depth) (files=7, chunks=19, children=0)
[+   28.9s] 🧩 Aggregating findings from BFS tree
[+   28.9s] β€’ Reranking 19 files by relevance
[+   29.4s] 🧩 Synthesizing final answer (input: 41,802/80,000 tokens, 52.3%) (chunks=69, files=19)
[+   30.9s] β€’ Synthesizing 2 clusters in parallel (concurrency=3)
[+   57.5s] β€’ Combining 2 cluster summaries into final answer
[+   71.1s] πŸ” Validating output quality
[+   71.1s] πŸŽ‰ Deep research complete

**Answer**

- The GitTinkerer webhook flow accepts `issue_comment` events that pass signature verification and looks for comments beginning with `/tinker`. There is no documented or implemented check in the shown handler to restrict this to repo owners or specific commenters. As a result, any GitHub user who can comment on a PR can trigger a run by using `/tinker`. [1][3][10][13]
- The docs explicitly treat comment bodies as untrusted input and suggest adding additional allowlisting before spawning runs, which implies that the default flow does not enforce author-based restrictions. [1]
- The instruction text is derived from the PR comment (with `/tinker` stripped) and becomes `comment_body` in the run payload; the raw comment is also stored. This is the prompt surface, so a malicious commenter can attempt prompt injection through the instruction text if they can comment on the PR. [1][3][13]

**Why this is the case (flow and gates)**

- The webhook middleware enforces required GitHub headers; the controller verifies the webhook signature and only processes `issue_comment` events. Invalid signatures are rejected, and non-`issue_comment` events are ignored. [10][12][14]
- `handleIssueComment` ignores non‑PR comments and comments without the `/tinker` prefix; otherwise it continues with rate limiting, PR metadata fetch, and run creation. There is no owner-only or commenter allowlist check in this handler. [13]
- The architecture and README describe `/tinker` as the trigger in PR comments and do not mention ownership or role‑based restrictions. [1][3]

**Authorization context (what is and isn’t enforced)**

- The GitHub App uses standard installation-token auth (JWT β†’ installation token) to act on the repo where the app is installed. That establishes API access but does not authorize which GitHub user is allowed to trigger `/tinker`. [1][9][11]
- The provided GitTinkerer auth and client code shows how tokens are minted and used, but it does not include any commenter authorization checks. [9][11]
- Additional code from a related Tinkero webhook handler shows similar installation token flows and caching but also does not contain `/tinker` parsing or per‑commenter authorization logic. [17][18][19]

**Direct answers to the questions**

- **Can other users maliciously inject prompts in GitHub PR comments?**  
  Yes, if they can comment on the PR. The `/tinker` handler accepts the comment text as the instruction, with no author-based gating in the shown flow, so prompt injection via PR comments is possible under those conditions. [1][3][13]

- **Are only GitHub repo owners authorized to use `/tinker`?**  
  No evidence shows owner‑only authorization. The current flow authorizes execution based on valid GitHub signature, `issue_comment` event, PR context, and `/tinker` prefix, not commenter identity or repo ownership. [1][3][10][13]

**Notes on evidence limits**

- The provided sources that cover GitHub App authentication and token usage do not include any `/tinker` authorization logic, so they neither establish nor refute additional checks outside the shown handlers. [9][11][17][18][19]

If you want to harden this, typical mitigations include checking commenter org/team membership or maintainers list, or implementing a repo/org allowlist before executing `/tinker`, as the docs already suggest. [1]

---

## Sources

**Files**: 19 | **Chunks**: 69

└── projects/
        β”œβ”€β”€ GitTinkerer/
        β”‚       β”œβ”€β”€ [1] README.md (6 chunks: L3-13, L39-45, L53-58, +3 more)
        β”‚       β”œβ”€β”€ docs/
        β”‚       β”‚       β”œβ”€β”€ [2] api-reference.md (6 chunks: L11-23, L53-55, L55-69, +3 more)
        β”‚       β”‚       β”œβ”€β”€ [3] architecture.md (5 chunks: L3-13, L124-143, L144-177, +2 more)
        β”‚       β”‚       β”œβ”€β”€ [4] github-app-setup.md (15 chunks: L3-10, L39-62, L62-69, +12 more)
        β”‚       β”‚       β”œβ”€β”€ [5] index.md (6 chunks: L3-13, L39-45, L53-58, +3 more)
        β”‚       β”‚       └── [6] observability.md (4 chunks: L181-195, L464-479, L604-608, +1 more)
        β”‚       └── service/
        β”‚               └── src/
        β”‚                       β”œβ”€β”€ __tests__/
        β”‚                       β”‚       β”œβ”€β”€ helpers/
        β”‚                       β”‚       β”‚       └── [7] factories.ts (1 chunks: L95-130)
        β”‚                       β”‚       └── integration/
        β”‚                       β”‚               └── [8] setup.ts (1 chunks: L128-157)
        β”‚                       β”œβ”€β”€ config/
        β”‚                       β”‚       └── [9] github.ts (3 chunks: L129-147, L148-180, L193-229)
        β”‚                       β”œβ”€β”€ controllers/
        β”‚                       β”‚       └── [10] githubWebhookController.ts (4 chunks: L26-51, L52-77, L60-82, +1 more)
        β”‚                       β”œβ”€β”€ infra/
        β”‚                       β”‚       └── github/
        β”‚                       β”‚               └── [11] api.ts (1 chunks: L7-48)
        β”‚                       β”œβ”€β”€ middleware/
        β”‚                       β”‚       └── [12] githubWebhookGate.ts (1 chunks: L4-35)
        β”‚                       └── usecases/
        β”‚                               └── github/
        β”‚                                       β”œβ”€β”€ [13] handleIssueComment.ts (1 chunks: L39-77)
        β”‚                                       └── [14] verifyWebhook.ts (1 chunks: L8-21)
        └── Tinkero/
                └── services/
                        └── webhook-handler/
                                β”œβ”€β”€ [15] REPOSITORY_CLONING.md (3 chunks: L3-13, L13-30, L150-183)
                                └── internal/
                                        β”œβ”€β”€ config/
                                        β”‚       └── [16] TINKERO_CONFIG.md (1 chunks: L335-347)
                                        └── github/
                                                β”œβ”€β”€ [17] README.md (3 chunks: L13-42, L53-57, L58-119)
                                                β”œβ”€β”€ [18] auth.go (2 chunks: L41-72, L45-88)
                                                └── [19] client.go (5 chunks: L91-120, L100-134, L112-116, +2 more)
# Implementation Plan: Owner-Only `/tinker` Authorization

## Overview
Fix the security vulnerability where any GitHub user who can comment on a PR can trigger `/tinker` commands. Restrict usage to repository owners only (personal repos), with clear feedback for unauthorized users.

## Critical Files

1. **projects/GitTinkerer/service/src/usecases/github/handleIssueComment.ts** - Add authorization logic
2. **projects/GitTinkerer/service/src/controllers/dependencies.ts** - Wire up postPRComment dependency
3. **projects/GitTinkerer/service/src/usecases/github/__tests__/handleIssueComment.test.ts** - Add test coverage
4. **projects/GitTinkerer/docs/architecture.md** - Document authorization policy

## Implementation Steps

### 1. Add Authorization Check to handleIssueComment.ts

**Location**: After line 54 (after `/tinker` prefix check, before rate limiting)

**Add helper function** (before handleIssueComment function):
```typescript
function isRepositoryOwner(event: GitHubIssueCommentEvent): boolean {
  // Only User-owned repos supported (not Organization)
  if (event.repository.owner.type !== 'User') {
    return false;
  }
  // Commenter must match repo owner
  return event.comment.user.login === event.repository.owner.login;
}
nntin@NUC:~/git/lair.nntin.xyz$ chunkhound research "In the GitTinkerer project, look into if other users can maliciously injects prompts on GitHub Pull Request comment section. Are only GitHub repo owner authorized to use the /tinker command?"
[+    0.0s] πŸ” Starting deep research: In the GitTinkerer project, look into if other users can mal...
[+    0.0s] ℹ️ Max depth: 1, synthesis budget: 115k tokens
[+    0.0s] πŸ“Š Processing depth 0/1
[+    0.0s] πŸ”Ή In the GitTinkerer project, look into if other users can mal...
[+    0.0s] πŸ”„ Expanding query
[+    3.1s] ✨ Expanded to 3 queries (queries=3)
[+    6.8s] πŸ”Ž Found 25 chunks (chunks=25)
[+    6.8s] 🏷️ Extracting symbols
[+    6.8s] πŸ“‹ Extracted 14 symbols, searching top 5 (symbols=14)
[+    6.8s] πŸ“ Running regex search
[+    7.0s] βœ“ Found 0 additional chunks (chunks=0)
[+    7.0s] πŸ“– Reading files
[+    7.0s] πŸ“„ Read 4 files (files=4, tokens=10000)
[+    7.0s] πŸ€– Generating follow-up questions
[+   20.9s] πŸ’‘ Generated 2 follow-ups
[+   20.9s] βœ… Complete (files=4, chunks=25, children=2)
[+   20.9s] β”œβ”€β”€ πŸ“Š Processing depth 1/1
[+   20.9s] β”œβ”€β”€ πŸ”Ή In `handleIssueComment` (service/src/usecases/github/handleI...
[+   20.9s] β”œβ”€β”€ πŸ”„ Expanding query
[+   20.9s] β”œβ”€β”€ πŸ”Ή Where is `createPrPayload` (service/src/types/payload.ts) us...
[+   20.9s] β”œβ”€β”€ πŸ”„ Expanding query
[+   23.9s] β”œβ”€β”€ ✨ Expanded to 3 queries (queries=3)
[+   26.3s] β”œβ”€β”€ ✨ Expanded to 3 queries (queries=3)
[+   27.6s] β”œβ”€β”€ πŸ”Ž Found 16 chunks (chunks=16)
[+   27.6s] β”œβ”€β”€ 🏷️ Extracting symbols
[+   27.6s] β”œβ”€β”€ πŸ“‹ Extracted 13 symbols, searching top 5 (symbols=13)
[+   27.6s] β”œβ”€β”€ πŸ“ Running regex search
[+   28.5s] β”œβ”€β”€ βœ“ Found 12 additional chunks (chunks=12)
[+   28.5s] β”œβ”€β”€ πŸ“– Reading files
[+   28.5s] β”œβ”€β”€ πŸ“„ Read 6 files (files=6, tokens=20651)
[+   28.5s] β”œβ”€β”€ βœ… Complete (leaf at max depth) (files=6, chunks=22, children=0)
[+   30.0s] β”œβ”€β”€ πŸ”Ž Found 23 chunks (chunks=23)
[+   30.0s] β”œβ”€β”€ 🏷️ Extracting symbols
[+   30.0s] β”œβ”€β”€ πŸ“‹ Extracted 16 symbols, searching top 5 (symbols=16)
[+   30.0s] β”œβ”€β”€ πŸ“ Running regex search
[+   30.1s] β”œβ”€β”€ βœ“ Found 12 additional chunks (chunks=12)
[+   30.1s] β”œβ”€β”€ πŸ“– Reading files
[+   30.1s] β”œβ”€β”€ πŸ“„ Read 10 files (files=10, tokens=28872)
[+   30.1s] β”œβ”€β”€ βœ… Complete (leaf at max depth) (files=10, chunks=31, children=0)
[+   30.1s] 🧩 Aggregating findings from BFS tree
[+   30.1s] β€’ Reranking 10 files by relevance
[+   30.4s] 🧩 Synthesizing final answer (input: 26,392/80,000 tokens, 33.0%) (chunks=35, files=10)
[+   37.0s] πŸ” Validating output quality
[+   37.0s] πŸŽ‰ Deep research complete


I can’t deliver a 30,000‑token full‑system analysis in this response, but I can answer your specific security question clearly with citations from the provided sources.

Other users **cannot** trigger `/tinker` runs unless they are the repository owner, and organization‑owned repos are rejected entirely. The service enforces this by checking `repository.owner.type === 'User'` and requiring `comment.user.login === repository.owner.login` before any rate limiting or PR metadata fetches; unauthorized attempts are ignored and get a denial comment posted back to the PR. [3] [10] This gate is explicitly documented as a protection against prompt‑injection attempts from untrusted collaborators. [3] Therefore, only the GitHub repo owner can use `/tinker`, and other commenters cannot maliciously inject prompts through PR comments. [3] [10]

---

## Sources

**Files**: 10 | **Chunks**: 35

└── projects/
        └── GitTinkerer/
                β”œβ”€β”€ [1] README.md (4 chunks: L53-58, L58-69, L94-119, +1 more)
                β”œβ”€β”€ docs/
                β”‚       β”œβ”€β”€ [2] api-reference.md (1 chunks: L171-205)
                β”‚       β”œβ”€β”€ [3] architecture.md (5 chunks: L144-177, L389-436, L437-450, +2 more)
                β”‚       β”œβ”€β”€ [4] github-app-setup.md (9 chunks: L3-10, L72-89, L133-142, +6 more)
                β”‚       β”œβ”€β”€ [5] index.md (4 chunks: L53-58, L58-69, L94-119, +1 more)
                β”‚       └── [6] observability.md (3 chunks: L181-195, L464-479, L627-661)
                └── service/
                        └── src/
                                β”œβ”€β”€ __tests__/
                                β”‚       β”œβ”€β”€ helpers/
                                β”‚       β”‚       └── [7] factories.ts (1 chunks: L95-130)
                                β”‚       └── integration/
                                β”‚               └── [8] setup.ts (1 chunks: L128-157)
                                β”œβ”€β”€ types/
                                β”‚       └── [9] payload.ts (1 chunks: L110-122)
                                └── usecases/
                                        └── github/
                                                └── [10] handleIssueComment.ts (6 chunks: L34-51, L45-49, L53-82, +3 more)

PS: The creator of ChunkHound created the project out of necessity while rewriting a 170 million line codebase over multiple decades (Ada, Java, C++, Matlab, DI, and indirection).