MetaMask / MetaMask/metamask-mobile
[Bug]: Unsanitized user Input GraphQL Queries via user-controlled Issue titles and labels
- Dominant language
- TypeScript
- Stars
- 3k
- Forks
- 1.7k
- Avg merge
- 1d 14h
- Merged PRs (30d)
- 669
Description
### Describe the bug
/cc @ptrgits
https://github.com/metamask/metamask-mobile/blob/95acabf33ae87c43144a2a84bc8e26d2e26bb826/.github/scripts/close-release-bug-report-issue.ts#L32-L37
https://github.com/metamask/metamask-mobile/blob/95acabf33ae87c43144a2a84bc8e26d2e26bb826/.github/scripts/close-release-bug-report-issue.ts#L46-L46
https://github.com/metamask/metamask-mobile/blob/95acabf33ae87c43144a2a84bc8e26d2e26bb826/.github/scripts/close-release-bug-report-issue.ts#L97-L97
https://github.com/metamask/metamask-mobile/blob/95acabf33ae87c43144a2a84bc8e26d2e26bb826/.github/scripts/close-release-bug-report-issue.ts#L115-L115
A issue in the GitHub automation scripts where database queries are constructed from user-controlled sources without proper sanitization. This exposes the project to potential SQL injection attacks through GitHub issue titles and labels.
The issue exists in `.github/scripts/close-release-bug-report-issue.ts` at the following lines:
1. **Lines 32-37**: Direct string concatenation with issue data
```typescript
const query = `
query {
repository(owner: "${owner}", name: "${repo}") {
issue(number: ${issueNumber}) {
title
labels(first: 100) {
nodes {
name
}
}
}
}
}
`;
```
2. **Line 46**: User-controlled input embedded in query
```typescript
const issue = result.data.repository.issue;
```
3. **Line 97**: User input used in database operation context
```typescript
if (labels.some((label: { name: string }) => label.name === 'Release Bug')) {
```
4. **Line 115**: Direct usage of user-provided data
```typescript
const title = issue.title;
```
The vulnerability occurs because:
- Issue titles and labels are user-controlled inputs
- These inputs are directly embedded into GraphQL queries without parameterization
- Malicious actors could inject special characters or GraphQL operations through crafted issue titles/labels
### Proof of Concept
An attacker could create an issue with a title containing GraphQL injection payloads:
```
Regular Title'}) { __schema { types { name } } } #
```
Or through malicious label names that break the intended query structure.
### Impact
- Unauthorized data access through GraphQL query injection
- Potential exposure of sensitive repository information
- Disruption of GitHub automation workflows
- Escalation to other parts of the application if similar patterns exist elsewhere
### Recommended Fix
Replace string concatenation with parameterized queries using GraphQL variables:
```typescript
const query = `
query GetIssue($owner: String!, $repo: String!, $issueNumber: Int!) {
repository(owner: $owner, name: $repo) {
issue(number: $issueNumber) {
title
labels(first: 100) {
nodes {
name
}
}
}
}
}
`;
const variables = {
owner,
repo,
issueNumber
};
const result = await github.graphql(query, variables);
```
### References
- [GitHub GraphQL API Security](https://docs.github.com/en/graphql/guides/forming-calls-with-graphql#authenticating-with-graphql)
- [GraphQL Injection Prevention](https://cheatsheetseries.owasp.org/cheatsheets/GraphQL_Cheat_Sheet.html)
- [SQL Injection Prevention](https://owasp.org/www-community/attacks/SQL_Injection)
### Version
7.58.0
Contributor guide
Research direction
Start in .github/scripts/close-release-bug-report-issue.ts, especially lines 32-37, 46, 97, and 115, and trace which values enter the GraphQL request. Verify the reported injection path and inspect the script's existing checks before deciding on a safe change. Done means the reported user-controlled inputs cannot alter the query and the relevant automation behavior is covered by a regression check.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- github-actions, graphql, typescript
- Domain
- api, devops, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100