4.1 KiB
Security Model
Authentication vs Git Configuration
How User Identity Works
Question: Can't I just set my git username to anything and bypass validation?
Answer: No. The validation uses Gitea account authentication, not git commit authors.
Git Commit Author (NOT used for validation)
# This can be set to anything locally
git config user.name "anyone"
git config user.email "anyone@example.com"
git commit -m "My commit"
These values are NOT used for plugin ownership validation.
PR Creator (used for validation)
When you create a Pull Request:
- You must be logged into your Gitea account
- The PR is created through Gitea's authenticated API
github.event.pull_request.user.login= your authenticated Gitea username
This is what validation checks against.
Example Attack Scenario (Prevented)
❌ Attacker tries:
# Configure git to impersonate someone
git config user.name "victim"
git config user.email "victim@example.com"
# Modify victim's plugin
vim plugins/victim-plugin.json
# Change author to "attacker"
git commit -m "Update plugin"
git push
# Create PR (must log into Gitea as "attacker" account)
✅ What happens:
- PR is created by authenticated Gitea user:
attacker - Validation script receives:
prAuthor = "attacker" - Validation checks original plugin from main branch:
original.author = "victim" - Check fails:
"victim" !== "attacker" - Result: ❌
Cannot modify plugin owned by "victim" (you are "attacker")
The git commit author is irrelevant - what matters is who is logged into Gitea when creating the PR.
Security Measures
1. Dual Checkout
- Checkout main branch → base/ (trusted validation scripts)
- Checkout PR branch → pr/ (untrusted user submissions)
Validation script always runs from base/, never from PR branch.
2. Infrastructure Protection
PRs that modify .gitea/ directory are automatically rejected.
3. Ownership Verification
All modifications/deletions check original ownership from main branch:
// Check original plugin from main (base/)
const originalPlugin = readFile('../base/plugins/example.json');
// User can only modify if they own the original
if (originalPlugin.author !== prAuthor) {
reject("Cannot modify plugin owned by someone else");
}
4. Author Field Validation
New plugins must have author field matching the PR creator's authenticated Gitea username.
What About Collaboration?
Q: What if I want someone else to update my plugin?
A: They cannot submit PRs directly. Options:
- Transfer ownership by updating the
authorfield yourself - They fork your plugin repo and create their own plugin entry
- Add them as collaborators to your plugin repository (not the directory)
Trust Model
Trusted Components
- Main branch content (validated history)
- Gitea authentication system
- GitHub Actions runner environment
- Validation scripts on main branch
Untrusted Components
- PR branch content (user submissions)
- Git commit metadata (names, emails)
- PR descriptions and comments
Validation Flow
1. User authenticates to Gitea → Trusted user identity
2. User creates PR → github.event.pull_request.user.login
3. Validation runs from main branch scripts → Trusted code
4. Checks plugin ownership against main → Trusted ownership data
5. Validates PR author matches plugin author → Secure check
Reporting Security Issues
If you find a security vulnerability in the plugin directory system:
- Do NOT create a public issue or PR
- Contact the repository maintainer directly
- Provide detailed reproduction steps
- Allow time for a fix before public disclosure
Additional Safeguards
Rate Limiting
Gitea's built-in rate limiting prevents spam PR attacks.
Branch Protection
The main branch is protected:
- Direct pushes disabled
- All changes via PR
- Auto-merge only after validation passes
Audit Trail
All changes are tracked in git history:
- Who created the PR (Gitea account)
- What changed (git diff)
- When it was merged (git commit timestamp)
- Why validation passed (CI logs)