Dev.to Security 🔐 Cybersecurity 👁 0 📖 2 min read

Your Reviewers Approved the Line on Screen and the Compiler Read a Different One

The pull request came from outside the team. A small fix to the permissions check, with a helpful comment explaining it. Two people reviewed it. On screen the logic was clear. If the user is not an admin, stop here.

The pull request
came from outside the team.

A small fix
to the permissions check,
with a helpful comment
explaining it.

Two people reviewed it.

On screen
the logic was clear.

If the user is not an admin,
stop here.

The comment sat
at the end of the line,
where comments go.

They approved it.

Three weeks later
an ordinary account
deleted a project
it should never have been able to see.

The code that ran
was not the code they read.

Text has a direction.

English runs left to right.

Arabic and Hebrew
run right to left.

When the two are mixed
in one line,
Unicode has invisible control characters
that tell the screen
which way to lay each part out.

They are meant
for ordinary sentences,
a Hebrew word
inside an English one.

But they work anywhere,
including in source code.

Put the right ones
inside a comment
or a string,
and the editor
redraws the rest of the line.

Characters stored later
are shown earlier.

So code can be displayed
as if it sat inside a comment,
and a comment
as if it were code.

The compiler
does not lay anything out.

It reads the characters
in the order they are stored.

In 2021
two researchers at Cambridge,
Nicholas Boucher and Ross Anderson,
published this as Trojan Source.

They showed it working
in C, C++, C#, Java,
JavaScript, Python, Rust and Go.

And in what the review tools
of the day displayed.

Some tools have answered since.

GitHub puts a warning
above any file
that contains these characters.

The Rust compiler
rejects them in code by default.

GCC warns about them.

But your terminal,
a patch in an email,
an older review tool,
or code pasted into a chat
may show you nothing at all.

So do not rely on reading.

Add a check to CI
that fails on the bidirectional controls
anywhere in source.

U+202A to U+202E.

U+2066 to U+2069.

Real code
almost never needs them.

If a translation file does,
allow that file by name,
and only that file.

And treat a warning banner
on a diff
as a stop,
not as decoration.

Review is a person
reading what the screen shows.

The build
reads the bytes.

Make a machine
check that the two
are the same thing.

– Serguey Asael Shinder

📰 Read the original article on Dev.to Security

Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.