GitHub repository rulesets can block pushes containing files with restricted extensions like .exe. To resolve this, either remove the file from your commit, request a bypass from repository administrators, or update the repository rules if you have admin access.
This error occurs when GitHub's Push Protection feature detects that your commit contains a file with a restricted extension. Repository administrators can configure "push rules" that prevent certain file types from being pushed to protect the repository from potentially harmful or unwanted content. The GH013 error code specifically indicates a push rule violation. Unlike traditional branch protection rules that focus on who can push, push rules examine the content of what you're pushing - including file extensions, file paths, and file sizes. File extension restrictions are commonly used to block executable files (.exe, .dll, .so), scripts that could be malicious (.bat, .ps1), or files that shouldn't be in source control (.zip, .tar.gz). This helps prevent security risks and keeps repositories clean of binary files that don't version well in Git. Push rules are currently available for private and internal repositories on GitHub Enterprise Cloud and GitHub Team plans. The rules are evaluated server-side, meaning you won't see an error until you attempt to push.
The error message provides crucial information about what's being blocked:
remote: error: GH013: Push rule violation - file extension .exe is not allowed
remote:
remote: Review the rules at http://github.com/owner/repo/rules?ref=refs/heads/mainKey things to note:
- The specific file extension being blocked (e.g., .exe)
- The branch being pushed to (refs/heads/main)
- The link to review repository rules
Click the rules link to see the full configuration and understand what restrictions are in place.
Find all files with the restricted extension in your pending commits:
# List all files with .exe extension staged or in recent commits
git diff --name-only origin/main HEAD | grep -E '\.exe$'
# Or check for multiple extensions
git diff --name-only origin/main HEAD | grep -E '\.(exe|dll|apk|so)$'
# See files in the last commit
git show --name-only HEAD | grep -E '\.exe$'
# Find files in your working directory
find . -name "*.exe" -not -path "./.git/*"Make note of which files are triggering the violation - you'll need to decide how to handle each one.
If you don't need the files in version control, remove them from your commit:
If the file is in your latest commit:
# Unstage and remove from last commit
git reset --soft HEAD~1
git rm --cached path/to/file.exe
git commit -m "Your original commit message"If the file is in multiple commits (use interactive rebase):
# Find which commits contain the file
git log --all --full-history -- "path/to/file.exe"
# Rebase from before the first commit with the file
git rebase -i <commit-before-file-was-added>
# In the editor, mark those commits as "edit"
# Then remove the file from each commit
git rm --cached path/to/file.exe
git commit --amend --no-edit
git rebase --continueAfter removing, add to .gitignore:
echo "*.exe" >> .gitignore
git add .gitignore
git commit -m "Add .exe files to gitignore"If you legitimately need the file in the repository, you may be able to request a bypass:
For repositories with bypass permissions:
Some organizations configure push rules to allow certain users, teams, or GitHub Apps to bypass restrictions.
Steps to request bypass:
1. Contact your repository administrator or security team
2. Explain why the file is necessary
3. Ask if an exception can be granted for your specific case
Check if you have bypass permissions:
- Go to the repository's Settings > Rules > Rulesets
- Look for the ruleset blocking your extension
- Check the "Bypass list" to see if your account is included
For GitHub Actions workflows:
If you're pushing from a workflow, you may need to use a GitHub App with bypass permissions:
- uses: actions/checkout@v4
with:
persist-credentials: false
token: ${{ secrets.APP_TOKEN }}If you're a repository administrator, you can modify the push rules:
Access the rulesets:
1. Go to your repository on GitHub
2. Click Settings > Rules > Rulesets
3. Find the ruleset containing the file extension restriction
Edit the restriction:
1. Click on the ruleset name to edit
2. Find "Restrict file extensions" under push rules
3. Options:
- Remove the specific extension from the block list
- Delete the entire extension restriction rule
- Add exceptions for specific paths
Add a bypass for specific users/teams:
1. In the ruleset, scroll to "Bypass list"
2. Add specific users, teams, or GitHub Apps
3. They will be able to push files with restricted extensions
Create a more targeted rule:
# Instead of blocking all .exe files, block specific paths
# Use file path restrictions instead:
build/*.exe
dist/*.exeImportant: Think carefully before removing security rules - they exist to protect your repository.
Binary files like executables often shouldn't be in Git repositories. Consider alternatives:
Git LFS (Large File Storage):
# Install Git LFS
git lfs install
# Track the file type
git lfs track "*.exe"
# Commit the .gitattributes
git add .gitattributes
git commit -m "Track .exe files with Git LFS"Note: Push rules may still block LFS pointer files if configured to block all files with that extension. Check with your administrator.
GitHub Releases:
Store binaries in GitHub Releases instead:
1. Build your executable
2. Create a GitHub release
3. Upload the binary as a release asset
4. Reference it in your README
External storage:
For build artifacts, use dedicated storage:
- AWS S3 or Google Cloud Storage
- Azure Blob Storage
- Artifact repositories (Artifactory, Nexus)
- Package registries (npm, PyPI, NuGet)
CI/CD artifacts:
Let your CI system handle binary builds:
# GitHub Actions example
- uses: actions/upload-artifact@v4
with:
name: my-executable
path: build/app.exeIf blocked files exist deep in your commit history, you may need to rewrite history:
Using git filter-repo (recommended):
# Install git-filter-repo
pip install git-filter-repo
# Remove all .exe files from history
git filter-repo --invert-paths --path-glob "*.exe"
# Re-add remote and push
git remote add origin https://github.com/owner/repo.git
git push origin main --forceUsing BFG Repo-Cleaner:
# Clone a fresh mirror
git clone --mirror https://github.com/owner/repo.git
cd repo.git
# Remove files matching pattern
bfg --delete-files "*.exe"
# Clean up and push
git reflog expire --expire=now --all
git gc --prune=now --aggressive
git push --forceWarning: This rewrites Git history. All collaborators will need to re-clone or rebase their work. Coordinate with your team before force pushing.
Set up guardrails to catch these issues before pushing:
Update .gitignore:
# Add to .gitignore
cat >> .gitignore << 'EOF'
# Executables
*.exe
*.dll
*.so
*.dylib
*.apk
*.app
# Installer files
*.msi
*.dmg
*.deb
*.rpm
# Archives (if blocked)
*.zip
*.tar.gz
*.rar
*.7z
EOF
git add .gitignore
git commit -m "Add blocked file types to gitignore"Create a pre-commit hook:
cat > .git/hooks/pre-commit << 'EOF'
#!/bin/bash
# Check for files with blocked extensions
BLOCKED_EXTENSIONS="exe|dll|so|apk|msi"
files=$(git diff --cached --name-only | grep -E "\.($BLOCKED_EXTENSIONS)$")
if [ -n "$files" ]; then
echo "Error: Attempting to commit files with blocked extensions:"
echo "$files"
echo ""
echo "These files will be rejected by GitHub push rules."
echo "Remove them with: git rm --cached <file>"
exit 1
fi
EOF
chmod +x .git/hooks/pre-commitUse pre-commit framework for team-wide enforcement:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.5.0
hooks:
- id: check-executables-have-shebangs
- id: forbid-files
args: ['--pattern', '\.(exe|dll|so|apk)$']### Understanding GitHub Push Rules
Push rules are part of GitHub's repository rulesets feature, introduced to give administrators fine-grained control over what can be pushed to a repository. Unlike branch protection rules that control who can push, push rules examine the content of commits.
Available push rule types:
- File extension restrictions: Block specific extensions (.exe, .dll, etc.)
- File path restrictions: Block files in specific directories
- File size restrictions: Block files over a certain size
- Commit message patterns: Require specific formats in commit messages
### GH013 vs Other Error Codes
GitHub uses different error codes for different push protection features:
| Code | Feature | Description |
|------|---------|-------------|
| GH001 | File size | File exceeds GitHub's size limit (100 MB) |
| GH013 | Push rules | Repository ruleset violation |
| GH006 | Protected branch | Branch protection rule violation |
### Push Rules Availability
Push rules have specific availability requirements:
- GitHub Enterprise Cloud: Full support
- GitHub Team: Full support
- GitHub Free: Not available for rulesets
- Public repositories: Limited support (some rules only work on private/internal repos)
### Bypass Permissions
Administrators can configure bypass permissions in rulesets:
1. Always bypass: Certain users can always push restricted content
2. Request bypass: Users can request temporary exceptions
3. GitHub Apps: Specific apps can bypass (useful for CI/CD)
4. Deploy keys: Can be given bypass permissions
### Common Restricted Extensions
Many organizations block these extensions by default:
Executables:
- .exe, .dll, .so, .dylib
- .app, .apk, .ipa
- .jar, .war
Scripts (if security-sensitive):
- .bat, .cmd, .ps1
- .sh (less common)
Installers:
- .msi, .dmg, .deb, .rpm
Archives:
- .zip, .tar.gz, .rar, .7z
### Working Around Restrictions Legitimately
If you genuinely need versioned binaries:
1. Use Git LFS: Store actual files externally, keep pointers in repo
2. Use separate repositories: Binary artifacts in a dedicated repo
3. Use package registries: npm, PyPI, NuGet, Docker Hub
4. Use release assets: Attach binaries to GitHub releases
5. Request exception: Talk to your security team about legitimate needs
### Ruleset vs Branch Protection
Understanding the difference:
Branch protection rules (older):
- Protect specific branches
- Control who can push
- Require reviews, status checks
- Applied per-branch
Repository rulesets (newer):
- Can apply to multiple branches via patterns
- Include push rules (content inspection)
- Support bypass lists
- More flexible targeting
### API Access to Push Rules
If you need to programmatically check or modify rules:
# List rulesets via API
gh api repos/{owner}/{repo}/rulesets
# Get specific ruleset
gh api repos/{owner}/{repo}/rulesets/{ruleset_id}
# Check what rules apply to a branch
gh api repos/{owner}/{repo}/rules/branches/{branch}kex_exchange_identification: Connection closed by remote host
Connection closed by remote host when connecting to Git server
fatal: unable to access: Proxy auto-configuration failed
How to fix 'Proxy auto-configuration failed' in Git
fatal: unable to access: Authentication failed (proxy requires basic auth)
How to fix 'Authentication failed (proxy requires basic auth)' in Git
fatal: unable to access: no_proxy configuration not working
How to fix 'no_proxy configuration not working' in Git
fatal: unable to read tree object in treeless clone
How to fix 'unable to read tree object in treeless clone' in Git