Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions src/Mvc/Mvc.Core/src/Routing/UrlHelperBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -60,7 +60,7 @@ public virtual bool IsLocalUrl(string url)
// url doesn't start with "//" or "/\"
if (url[1] != '/' && url[1] != '\\')
{
return true;
return !HasControlCharacter(url.AsSpan(1));
}

return false;
Expand All @@ -78,15 +78,30 @@ public virtual bool IsLocalUrl(string url)
// url doesn't start with "~//" or "~/\"
if (url[2] != '/' && url[2] != '\\')
{
return true;
return !HasControlCharacter(url.AsSpan(2));
}

return false;
}

return false;

static bool HasControlCharacter(ReadOnlySpan<char> readOnlySpan)
{
// URLs may not contain ASCII control characters.
for (var i = 0; i < readOnlySpan.Length; i++)
{
if (char.IsControl(readOnlySpan[i]))
{
return true;
}
}

return false;
}
}


/// <inheritdoc />
public virtual string Content(string contentPath)
{
Expand Down
39 changes: 38 additions & 1 deletion src/Mvc/Mvc.Core/test/Routing/UrlHelperTestBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
Expand Down Expand Up @@ -288,6 +288,43 @@ public void IsLocalUrl_RejectsInvalidTokenUrls(string url)
Assert.False(result);
}

[Theory]
[InlineData("\n")]
[InlineData("\\n")]
[InlineData("/\n")]
[InlineData("~\n")]
[InlineData("~/\n")]
public void IsLocalUrl_RejectsUrlWithNewLineAtStart(string url)
{
// Arrange
var helper = CreateUrlHelper(appRoot: string.Empty, host: "www.mysite.com", protocol: null);

// Act
var result = helper.IsLocalUrl(url);

// Assert
Assert.False(result);
}

[Theory]
[InlineData("/\r\nsomepath")]
[InlineData("~/\r\nsomepath")]
[InlineData("/some\npath")]
[InlineData("~/some\npath")]
[InlineData("\\path\b")]
[InlineData("~\\path\b")]
public void IsLocalUrl_RejectsUrlWithControlCharacters(string url)
{
// Arrange
var helper = CreateUrlHelper(appRoot: string.Empty, host: "www.mysite.com", protocol: null);

// Act
var result = helper.IsLocalUrl(url);

// Assert
Assert.False(result);
}

[Fact]
public void RouteUrlWithDictionary()
{
Expand Down