A Reminder to Watch Your Dependencies

I decided to take a bit of a shortcut on adding link previews to the Kyanite Facebook archive viewer. Rather than write the whole thing from scratch I figured maybe there was an OpenGraph rendering library already out there. Turned out there were a few for reading/parsing OpenGraph metadata, not that that is too hard either, but one which seemed okay at rendering it, link_preview_flutter. After a little playing it seemed to mostly “just work” but it was choking on cases where there wasn’t OpenGraph data or images in the data. I decided to be a good open source citizen and fork it to tweak it to handle those cases. That’s where my concern began.

With the fork in hand I tried to dutifully build the project but ran into an error about a missing Environment.API_URL field. That’s weird. It came down to the network call to get the open graph data:

final response = await http.get(
  Uri.parse(Environment.API_URL + url),
  // Send authorization headers to the backend.
  headers: {
	'Authorization': Environment.API_TOKEN,
  },
);

Wait, what is this? Send data to “the backend”? What backend? OpenGraph works by directly pulling the data from the site you are trying to get data on and parsing it. There is no need for a backend. It made no sense to be needing to relay the request to some other server to have it then echo a cleaned up response. It was at this point that I decided to just roll the UI myself and use one of the OpenGraph libraries that just made a direct call. Even that is a bit unnecessary since it’s just an HTTP request and searching for four fields in the header. It does get back to having too much of a sense of complacency on cybersecurity though.

This is a common problem with any modern development platform where we look for convenience in the wealth of discoverable libraries, often made by people and/or companies of all sizes. We know there will be bugs in any code including code we inherit. There could be some very egregious ones, like with Heartbleed in OpenSSH, to innocuous ones. However there can also be nefarious actors. Attacks like the SolarWinds hack could just as easily pop up in one of the many dependencies we pull in.Hypothetically open source allows us to discover that easier but that assumes that we are looking at the code itself. If I hadn’t forked this project to fix some other problem I would have never known that every link preview request any user of my application made was being reflected off another server. In the hands of a nefarious actor it would be a perfect data vacuuming technique.

Do I think the developer here is doing anything nefarious? No. In this case it looks like a holdover to a service implementation they did for Angular that they decided to just quickly whip up in Flutter. The point isn’t the intent of this particular developer in this particular instance. It is about a general problem of cybersecurity complacency that I’ve obviously let myself fall into. There are no silver bullet fixes either. Do you just take libraries from major developers? Looking at the version history, like count, etc. I knew it was a small library from a small developer. Should I have shunned them for that? Largeness isn’t always a guarantee of good coding and/or behaviors and smallness isn’t necessarily indicative of the opposite. Obviously a reviewer of my own Result Monad library would have similar questions about small developers. There is something about smaller developers that make us rightfully a little leery. That often falls into the realm of unknown code quality and how long it’d be supported. Of course large companies ditch libraries often too and can produce bad code, so again the “go for the large ones” is false security in and of itself.

In the end this was an innocuous reminder to resharpen my cybersecurity situational awareness. It is also maybe something that the pub.dev project can include in their checklists when looking at code. That’d be something like a validated table of what sort of system access it is going to have, if it echos data to third-party servers, etc. It seems something like that should jump out as much as code coverage and other automatically generated metrics.