Skip to content

Commit 5211d89

Browse files
committed
Fail closed when link-checker-api webhook secret is missing
verify_signature returned silently when the configured webhook secret was nil, allowing any unsigned POST to mark a LinkCheckerApiReport as completed. Reply 503 instead so the callback action never runs without a secret.
1 parent d565e2a commit 5211d89

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

app/controllers/admin/link_checker_api_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ def callback
1818
private
1919

2020
def verify_signature
21-
return unless webhook_secret_token
21+
return head :service_unavailable unless webhook_secret_token
2222

2323
given_signature = request.headers["X-LinkCheckerApi-Signature"]
2424
return head :bad_request unless given_signature

test/functional/admin/link_checker_api_controller_test.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,33 @@ def generate_signature(body, key)
3737

3838
assert_response :success
3939
end
40+
41+
test "POST :callback returns 503 when the webhook secret is not configured" do
42+
Rails.application.credentials.stubs(:link_checker_api_secret_token).returns(nil)
43+
LinkCheckerApiReport.any_instance.expects(:mark_report_as_completed).never
44+
45+
body = link_checker_api_batch_report_hash(id: 5, links: [{ uri: @link, status: "ok" }])
46+
post :callback, params: body
47+
48+
assert_response :service_unavailable
49+
end
50+
51+
test "POST :callback returns 400 when the signature header is missing" do
52+
LinkCheckerApiReport.any_instance.expects(:mark_report_as_completed).never
53+
54+
body = link_checker_api_batch_report_hash(id: 5, links: [{ uri: @link, status: "ok" }])
55+
post :callback, params: body
56+
57+
assert_response :bad_request
58+
end
59+
60+
test "POST :callback returns 400 when the signature does not match the body" do
61+
LinkCheckerApiReport.any_instance.expects(:mark_report_as_completed).never
62+
63+
body = link_checker_api_batch_report_hash(id: 5, links: [{ uri: @link, status: "ok" }])
64+
request.headers["X-LinkCheckerApi-Signature"] = generate_signature(body.to_json, "wrong-secret")
65+
post :callback, params: body
66+
67+
assert_response :bad_request
68+
end
4069
end

0 commit comments

Comments
 (0)