mirror of
https://github.com/coder/coder.git
synced 2026-09-22 05:05:20 +08:00
fix(coderd): reject workspace proxy hostname prefixes (#27544)
A workspace proxy hostname prefix could be accepted as a valid proxy access URL. An authenticated user could then be redirected to an attacker-controlled domain with an application-connect API key in the URL. Require proxy access URL matches to have a hostname boundary after the candidate hostname, allowing only the end of the URL, a port, or a path. Add regression coverage for proxy access URL and wildcard hostname prefixes. Refs: https://linear.app/codercom/issue/PLAT-384 --------- Co-authored-by: Bobby Ho <bobbidinho@gmail.com>
This commit is contained in:
@@ -2045,6 +2045,16 @@ func TestProxyByHostname(t *testing.T) {
|
||||
accessURL: "https://two.coder.com",
|
||||
wildcardHostname: "*--suffix.two.coder.com",
|
||||
},
|
||||
{
|
||||
name: "three",
|
||||
accessURL: "https://three.coder.com:8443",
|
||||
wildcardHostname: "*.wildcard.three.coder.com",
|
||||
},
|
||||
{
|
||||
name: "four",
|
||||
accessURL: "https://four.coder.com/",
|
||||
wildcardHostname: "*.wildcard.four.coder.com",
|
||||
},
|
||||
}
|
||||
for _, p := range proxies {
|
||||
dbgen.WorkspaceProxy(t, db, database.WorkspaceProxy{
|
||||
@@ -2075,6 +2085,34 @@ func TestProxyByHostname(t *testing.T) {
|
||||
allowWildcardHost: true,
|
||||
matchProxyName: "one",
|
||||
},
|
||||
{
|
||||
name: "MatchAccessURLWithPort",
|
||||
testHostname: "three.coder.com",
|
||||
allowAccessURL: true,
|
||||
allowWildcardHost: false,
|
||||
matchProxyName: "three",
|
||||
},
|
||||
{
|
||||
name: "MatchAccessURLWithTrailingSlash",
|
||||
testHostname: "four.coder.com",
|
||||
allowAccessURL: true,
|
||||
allowWildcardHost: false,
|
||||
matchProxyName: "four",
|
||||
},
|
||||
{
|
||||
name: "RejectAccessURLPrefix",
|
||||
testHostname: "one.coder",
|
||||
allowAccessURL: true,
|
||||
allowWildcardHost: false,
|
||||
matchProxyName: "",
|
||||
},
|
||||
{
|
||||
name: "RejectAccessURLTLDPrefix",
|
||||
testHostname: "one.coder.co",
|
||||
allowAccessURL: true,
|
||||
allowWildcardHost: false,
|
||||
matchProxyName: "",
|
||||
},
|
||||
{
|
||||
name: "MatchWildcard",
|
||||
testHostname: "something.wildcard.one.coder.com",
|
||||
@@ -2082,6 +2120,13 @@ func TestProxyByHostname(t *testing.T) {
|
||||
allowWildcardHost: true,
|
||||
matchProxyName: "one",
|
||||
},
|
||||
{
|
||||
name: "RejectWildcardHostnamePrefix",
|
||||
testHostname: "something.wildcard.one.coder",
|
||||
allowAccessURL: false,
|
||||
allowWildcardHost: true,
|
||||
matchProxyName: "",
|
||||
},
|
||||
{
|
||||
name: "MatchSuffix",
|
||||
testHostname: "something--suffix.two.coder.com",
|
||||
@@ -2089,6 +2134,13 @@ func TestProxyByHostname(t *testing.T) {
|
||||
allowWildcardHost: true,
|
||||
matchProxyName: "two",
|
||||
},
|
||||
{
|
||||
name: "RejectSuffixHostnamePrefix",
|
||||
testHostname: "something--suffix.two.coder",
|
||||
allowAccessURL: false,
|
||||
allowWildcardHost: true,
|
||||
matchProxyName: "",
|
||||
},
|
||||
{
|
||||
name: "ValidateHostname/1",
|
||||
testHostname: ".*ne.coder.com",
|
||||
|
||||
Generated
+1
-1
@@ -24212,7 +24212,7 @@ WHERE
|
||||
(
|
||||
(
|
||||
$2 :: bool = true AND
|
||||
url SIMILAR TO '[^:]*://' || $1 :: text || '([:/]?%)*'
|
||||
url SIMILAR TO '[^:]*://' || $1 :: text || '([:/]%)*'
|
||||
) OR
|
||||
(
|
||||
$3 :: bool = true AND
|
||||
|
||||
@@ -120,7 +120,7 @@ WHERE
|
||||
(
|
||||
(
|
||||
@allow_access_url :: bool = true AND
|
||||
url SIMILAR TO '[^:]*://' || @hostname :: text || '([:/]?%)*'
|
||||
url SIMILAR TO '[^:]*://' || @hostname :: text || '([:/]%)*'
|
||||
) OR
|
||||
(
|
||||
@allow_wildcard_hostname :: bool = true AND
|
||||
|
||||
Reference in New Issue
Block a user