Skip to main content

Dependency Confusion

Need

Ensuring secure and accurate dependency management

Context

  • Usage of Dart for building cross-platform mobile, web, and desktop applications
  • Usage of Shelf for managing and organizing data in a Node.js application
  • Usage of the http module for creating and handling HTTP servers

Description

Non compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:http/http.dart' as http;

void main() {
var app = shelf.Pipeline().addMiddleware(shelf.logRequests()).addHandler(_echoRequest);

io.serve(app, 'localhost', 8080);
}

shelf.Response _echoRequest(shelf.Request request) {
return shelf.Response.ok('Request for "${request.url}"');
}

The Dart code above represents a basic backend application using the shelf framework. The application listens to the localhost on port 8080 and responds with a simple message for each request it receives.

The vulnerability in this code is not in the Dart code itself, but in the pubspec.yaml file, which is used to manage Dart packages.

The dependencies section of the file is set to use any version of the shelf and http packages. This is a classic example of Dependency Confusion vulnerability. By not specifying a particular version for these packages, an attacker could potentially publish a malicious version of these packages and trick the package manager into installing it.

This could lead to the execution of harmful code when the application is run, as the malicious package could contain any code that the attacker chooses. This increases the possible attack vectors on the application.

To fix this vulnerability, it is recommended to always specify the exact version of the dependencies to be used. This way, the package manager will not be confused and will always install the correct and safe version of the packages.

Steps

  • Identify all the dependencies used in your project. In this case, the dependencies are 'shelf', 'shelf_io', and 'http'.
  • Ensure that the dependencies are correctly defined in your project's package manager file. For Dart, this would be the 'pubspec.yaml' file.
  • Specify the exact versions of the dependencies that your project requires. Avoid using version ranges or the latest version tag to prevent the package manager from getting confused.
  • Use a private package repository if possible. This can prevent an attacker from injecting malicious code into your project through a public repository.
  • Regularly update your dependencies to their latest secure versions. This can help to prevent dependency confusion attacks by ensuring that your project is not relying on outdated or insecure versions of dependencies.
  • Consider using dependency checking tools or services that can automatically check for and alert you to any potential security vulnerabilities in your project's dependencies.

Compliant code

import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as io;
import 'package:http/http.dart' as http;

void main() {
var app = shelf.Pipeline().addMiddleware(shelf.logRequests()).addHandler(_echoRequest);

io.serve(app, 'localhost', 8080);
}

shelf.Response _echoRequest(shelf.Request request) {
return shelf.Response.ok('Request for "${request.url}"');
}

The above code is a simple backend application written in Dart using the Shelf framework. It imports three packages: 'shelf', 'shelf_io', and 'http'. The application creates a server that listens on localhost at port 8080 and responds with a message containing the requested URL.

However, the code is vulnerable to a Dependency Confusion attack. This is because it does not specify the exact versions of the dependencies it requires. This can lead to ambiguity and confusion for the package manager, potentially allowing an attacker to execute harmful code by confusing the package manager into installing or updating the wrong versions of the dependencies.

To fix this vulnerability, the exact versions of the dependencies should be specified in the 'pubspec.yaml' file of the project. This file is used by Dart's package manager to manage the project's dependencies. Here is an example of how to specify the exact versions of the dependencies:

name: my_project
description: A simple backend application

environment:
sdk: '>=2.12.0 <3.0.0'

dependencies:
shelf: ^1.1.5
shelf_io: ^1.1.5
http: ^0.13.3

In this example, the '^' symbol before the version number indicates that the project can use any version that is compatible with the specified version. This still allows for some flexibility in the versions of the dependencies that can be used, while also ensuring that the package manager does not get confused and install or update to an incorrect or insecure version.

In addition to specifying the exact versions of the dependencies, it is also recommended to use a private package repository if possible, to regularly update the dependencies to their latest secure versions, and to use dependency checking tools or services to automatically check for potential security vulnerabilities in the project's dependencies.

References