WEBVTT

00:30.000 --> 00:31.800
Okay, so we are on time.

00:31.800 --> 00:33.800
Please take a seat if you're not sitting.

00:33.800 --> 00:35.800
And welcome, William.

00:35.800 --> 00:36.800
Thank you.

00:42.800 --> 00:44.600
Hey, everybody.

00:44.600 --> 00:46.200
Thank you for staying so late for my talk.

00:46.200 --> 00:50.200
I know it's pretty late, so I appreciate it.

00:50.200 --> 00:51.400
Today, I want to talk a little bit about it.

00:51.400 --> 00:52.200
A little bit about it.

00:52.200 --> 00:53.800
A couple of months ago, called Zizmour,

00:53.800 --> 00:55.000
and how I've been using it.

00:55.000 --> 00:55.400
It's a hunt for it.

00:55.400 --> 00:58.400
Get a back-ends box, and how you can use it as well.

00:58.400 --> 01:01.000
So just a little bit about myself.

01:01.000 --> 01:01.800
My name is William.

01:01.800 --> 01:03.200
That's my website.

01:03.200 --> 01:06.000
Currently I'm an engineering director at Trail of Bits.

01:06.000 --> 01:07.800
But this is not a work talk.

01:07.800 --> 01:11.200
And these slides, normal my opinions that I express throughout them,

01:11.200 --> 01:14.800
or the opinions of my employer.

01:14.800 --> 01:18.000
And outside of work, I'm also a maintainer of home brew,

01:18.000 --> 01:20.800
as well as a member of PIPA, and contributed to PIPA,

01:20.800 --> 01:22.200
and a few other things.

01:22.200 --> 01:25.000
So you'll see me possibly make my attention to some of those.

01:25.000 --> 01:27.800
And then if you want that QR code has these slides.

01:27.800 --> 01:30.400
And so if you want to follow along, there's some parts

01:30.400 --> 01:32.200
where you can try in real time.

01:32.200 --> 01:33.200
The things I'm going to show you.

01:33.200 --> 01:35.920
So you can try to exploit it in yourself.

01:35.920 --> 01:38.000
But I should just skip that.

01:38.000 --> 01:40.400
So let me do it and try to get a back-ends.

01:40.400 --> 01:42.320
I think I'll probably, actually, a quick show of hands.

01:42.320 --> 01:44.600
How many people have used get a back-ends in this room?

01:44.600 --> 01:45.800
OK, although only majority.

01:45.800 --> 01:48.200
So I'm not going to do too much of a intro.

01:48.200 --> 01:50.200
But there's a conclusion.

01:50.200 --> 01:51.600
It's get up to CIT offering.

01:51.600 --> 01:53.000
It's free for open source.

01:53.000 --> 01:54.800
It costs money, otherwise.

01:54.800 --> 01:57.680
It's a bunch of Yamohel.

01:57.680 --> 02:00.400
Work flows are, sort of, top-level units of execution.

02:00.400 --> 02:03.640
They contain jobs, jobs run on VMs, VMs, contain jobs that

02:03.640 --> 02:04.160
have steps.

02:04.160 --> 02:08.160
And each step is an independent sequence of shell commands

02:08.160 --> 02:11.960
or recomposed actions which contain themselves, other actions

02:11.960 --> 02:14.320
or shell commands.

02:14.320 --> 02:15.680
These can be checked out from other repos.

02:15.680 --> 02:17.600
So actions check out, actually, check out the actions check

02:17.600 --> 02:21.480
out repos and runs code from that repo.

02:21.480 --> 02:24.080
Those actions themselves are also Yamohel.

02:24.080 --> 02:25.360
They define reasonable operations

02:25.360 --> 02:27.560
that you can share between repositories.

02:27.560 --> 02:29.080
The official ones, which are generally under the actions

02:29.080 --> 02:32.640
namespace, as well as third-party ones, any public or private

02:32.640 --> 02:34.640
repo and GitHub, as well as local actions,

02:34.640 --> 02:36.440
as you can call an action that is defined somewhere

02:36.440 --> 02:37.640
in your own repository.

02:37.640 --> 02:41.000
If you have a checked out within your job,

02:41.000 --> 02:41.840
these are full-generally.

02:41.840 --> 02:44.520
They can run code, they can run other actions, et cetera.

02:44.520 --> 02:46.560
And importantly, they run in the context of the job

02:46.560 --> 02:49.160
that executes them, meaning that any sequence credentials, et cetera,

02:49.160 --> 02:51.640
that you give that job the action also has.

02:51.640 --> 02:54.280
And also, sort of, importantly, as we'll see later,

02:54.280 --> 02:56.440
they have file access to the jobs runner state,

02:56.440 --> 02:57.480
which includes the file system.

02:57.480 --> 02:59.760
Which contains all kinds of interesting and useful things,

02:59.760 --> 03:05.000
as well as other processes running on that VM.

03:05.000 --> 03:06.920
So bottom line, GitHub actions are arbitrary

03:06.920 --> 03:08.120
code executions of service.

03:08.120 --> 03:10.200
That will come up in various important ways

03:10.200 --> 03:13.280
throughout the stock.

03:13.280 --> 03:16.840
It's a very powerful system, GitHub actions.

03:16.840 --> 03:18.840
GitHub actions, it plugs into the broader permissions

03:18.840 --> 03:21.280
well that the GitHub offers.

03:21.280 --> 03:24.400
Every workflow runs for the latent secrets GitHub token

03:24.400 --> 03:27.680
or GitHub.token, depending on the context you're in.

03:27.680 --> 03:32.480
And by default, unless you opt into a more secure mode,

03:32.480 --> 03:33.560
this token has a lot of powers,

03:33.560 --> 03:36.320
including modifying the repo contents of the workflow,

03:36.320 --> 03:37.560
of the repo that contains the workflow

03:37.560 --> 03:40.200
that is loaded with it.

03:40.200 --> 03:42.160
If you are a workflow author, you can also up or downscope

03:42.160 --> 03:45.960
this credential, after you work flow job or step level

03:45.960 --> 03:49.000
with permissions box, which tell that scope of action,

03:49.000 --> 03:51.440
how many credentials it has, which you can't exceed

03:51.440 --> 03:53.680
with that default token.

03:53.680 --> 03:55.800
However, there's some wonky behavior there,

03:55.800 --> 03:57.760
where permissions are inherited from parent job

03:57.760 --> 04:00.600
or workflow context, if they're not set,

04:00.600 --> 04:02.040
but if they're explicitly set, they're shadowed.

04:02.040 --> 04:05.320
So they're not telescoping, they're shadowing, so that's.

04:05.320 --> 04:07.240
And again, this comes up in important ways.

04:07.240 --> 04:08.560
So of course, you can do things like on the right

04:08.560 --> 04:10.160
where you have the explicit readwriter

04:10.160 --> 04:13.440
and on permissions for each sort of scope,

04:13.440 --> 04:16.240
or you can set read all or you can do an empty object,

04:16.240 --> 04:18.640
which means, give me no permissions at all.

04:18.640 --> 04:19.920
However, that's so produces a token.

04:19.920 --> 04:24.040
And a token just gives you sort of larger rate limit limits,

04:24.040 --> 04:27.040
versus not having a token.

04:27.040 --> 04:30.240
Another way in which GitHub access is extremely powerful,

04:30.240 --> 04:31.880
which, again, will come up when we talk about the security,

04:31.880 --> 04:33.160
aspects of all of this, is that it has a,

04:33.160 --> 04:35.640
the extremely powerful expression system.

04:35.640 --> 04:37.960
Most parts of the workflow are action definition scheme

04:37.960 --> 04:41.200
in YAML support expressions, which are defined via

04:41.200 --> 04:43.120
this, like, curly syntax, where you put an expression

04:43.120 --> 04:45.040
in the middle, sometimes you don't need those curly,

04:45.040 --> 04:47.560
such as in an escondition.

04:47.560 --> 04:49.160
These are questions that have a lot of functionality

04:49.160 --> 04:50.160
within them.

04:50.160 --> 04:51.320
They can do math, they have control flow,

04:51.320 --> 04:53.880
they can encode and decode JSON and call a set of functions

04:53.880 --> 04:58.040
that are defined within the runner itself, et cetera.

04:58.040 --> 05:00.560
They can also directly, rather, when you expand them,

05:00.560 --> 05:03.560
they expand directly into other context references in them.

05:03.560 --> 05:06.440
So in this condition, then block a withinput,

05:06.440 --> 05:08.720
or even a run body, which contains, obviously, shell scripts

05:08.720 --> 05:09.400
that you're trying to run.

05:09.400 --> 05:13.960
You can expand values directly into the shell scripts.

05:13.960 --> 05:15.600
At the core of the expression system

05:15.600 --> 05:17.360
are these things that get up all's context,

05:17.360 --> 05:19.000
which are really just JSON objects.

05:19.000 --> 05:21.560
When the runner is invoked, it is loaded with a set of context,

05:21.560 --> 05:23.640
and you can access those contexts, sort of,

05:23.640 --> 05:26.120
is if they were, like, JSON script objects.

05:26.120 --> 05:28.360
So if you have nested dictionary,

05:28.360 --> 05:30.360
that has a secret stocked up token

05:30.360 --> 05:31.680
that gets modeled as the context,

05:31.680 --> 05:34.520
secret stocked up token, and the expression syntax.

05:34.520 --> 05:37.280
And these contexts come from both static and dynamic sources.

05:37.280 --> 05:39.640
So the static source is something that you define sort of,

05:39.640 --> 05:41.160
ahead of time, for the runner to load,

05:41.160 --> 05:42.800
so that's the one is configuration,

05:42.800 --> 05:45.040
as well as get inside states, to the event name,

05:45.040 --> 05:48.120
the event payload trigger, the workflow,

05:49.440 --> 05:51.960
and dynamic is symmetric expansions.

05:51.960 --> 05:54.240
I realize I have a way more stuff than I thought,

05:54.240 --> 05:56.120
so I'm going to kind of breeze through this.

05:56.120 --> 05:58.000
Even more powerful, you have these special variables,

05:58.000 --> 05:59.920
you can set environment variables, you can set the path,

05:59.920 --> 06:03.280
you can set variables between steps,

06:03.280 --> 06:05.200
you can set steps on trees.

06:05.200 --> 06:07.360
There's also a special file system state,

06:07.360 --> 06:08.840
like event path and tool cache,

06:08.840 --> 06:11.960
and these are, again, useful and we'll see.

06:11.960 --> 06:14.840
So now let's talk about the security of all of that.

06:14.840 --> 06:18.200
So before I do that, what is it in this matter?

06:18.200 --> 06:21.080
Well, one answer is it's well, the popular, and it does everything.

06:21.080 --> 06:23.120
That's a default choice for GitHub, meaning that,

06:23.120 --> 06:25.920
knowing people use it, pretty much everybody in this room uses it.

06:25.920 --> 06:28.720
As a corollary, it's used by developers with huge skill ranges,

06:28.720 --> 06:30.920
meaning that people who just want to get something done

06:30.920 --> 06:32.840
are using the same way people who are experts in SCD,

06:32.840 --> 06:36.000
deployment, and it has this massive range of uses,

06:36.000 --> 06:38.120
including most interestingly in the me,

06:38.120 --> 06:41.400
people publish the PIPI, et cetera, using GitHub actions,

06:41.400 --> 06:44.240
which means that the security of their package on those indices

06:44.240 --> 06:48.160
directly mirrors the security of the system that publishes that.

06:48.400 --> 06:51.600
So no one's the users, plus really powerful and complex

06:51.600 --> 06:52.680
to the system in security files.

06:52.680 --> 06:54.560
So let's break some of this stuff.

06:54.560 --> 06:59.040
OK, now crowd question, find the vulnerability on us.

06:59.040 --> 07:00.680
Let's see a few.

07:00.680 --> 07:02.800
Anybody know anybody know?

07:02.800 --> 07:06.200
Yep, OK, somebody's mentioned, right?

07:06.200 --> 07:08.160
What we're doing is we're expanding the value of GitHub event

07:08.160 --> 07:10.680
pull requests tied all directly into the shell context,

07:10.680 --> 07:11.720
which of course I can give it.

07:11.720 --> 07:13.240
Hello, cynical and cut it.

07:13.240 --> 07:16.160
See password, and now I'm running an arbitrary code.

07:16.160 --> 07:19.760
So again, the core thing here is, this is something

07:19.760 --> 07:21.080
that the attacker controls.

07:21.080 --> 07:23.760
The title is an attacker tool value that is loaded.

07:23.760 --> 07:26.000
Anybody can create a pull request on a public repository.

07:26.000 --> 07:28.840
If you put your title as, hello, some of you call one,

07:28.840 --> 07:31.160
cut it, see password, you're now running code in the context

07:31.160 --> 07:33.200
of the workflow that triggered it.

07:33.200 --> 07:34.880
That's baby steps.

07:34.880 --> 07:35.720
OK, what about this one?

07:35.720 --> 07:36.920
We've quoted it this time.

07:36.920 --> 07:38.840
Anybody see a problem?

07:38.840 --> 07:42.040
It's the same vulnerability.

07:42.040 --> 07:43.200
It's the same-down vulnerability.

07:43.200 --> 07:45.240
And the reason for this is going back to expressions.

07:45.240 --> 07:47.840
Expressions do not care about shell level voting,

07:47.840 --> 07:50.120
because they're injected by the actions runner

07:50.120 --> 07:53.240
before any shell processing happens.

07:53.240 --> 07:56.240
They have no chance for the shell to reparse,

07:56.240 --> 07:56.840
you've injected.

07:56.840 --> 07:58.600
It's exactly the same thing as SQL injection.

07:58.600 --> 08:00.080
You can code as much as you want in SQL injection,

08:00.080 --> 08:01.720
but if you're directly injecting the value,

08:01.720 --> 08:05.680
you can always inject in a scape, so the escaping.

08:05.680 --> 08:08.560
So in this case, our payload will be hello, quote, payload.

08:08.560 --> 08:10.080
And we get the exact same thing.

08:10.080 --> 08:12.600
So this is baby steps.

08:12.600 --> 08:13.840
OK.

08:13.840 --> 08:14.840
We'll see the vulnerability here.

08:25.480 --> 08:26.360
OK, that's enough time.

08:26.360 --> 08:28.720
So it's nothing about any other steps.

08:28.720 --> 08:30.160
All the steps are somatically correct.

08:30.160 --> 08:33.400
However, what happens is actions checkout.

08:33.400 --> 08:34.280
That's what we call out there.

08:34.280 --> 08:36.480
The first one, it persists silently

08:36.480 --> 08:38.000
to get up token by default.

08:38.000 --> 08:39.680
So when you run actions checkout,

08:39.680 --> 08:43.680
that context token that you use gets stored in.getconfig

08:43.680 --> 08:45.200
in the repo that you check out.

08:45.200 --> 08:48.640
Then, when you run actions, build up load artifact

08:48.640 --> 08:51.240
with the current directory as a path,

08:51.240 --> 08:53.880
you have now persisted your credential to a public artifact.

08:53.880 --> 08:56.240
Anybody who goes down with that artifact now

08:56.240 --> 08:57.600
has your credential.

08:57.600 --> 08:59.160
That credential's only alive for about four hours

08:59.160 --> 09:00.960
to find them correctly, but for four hours,

09:00.960 --> 09:03.280
you've now leaked potentially a global right

09:03.280 --> 09:05.720
credential figure repository.

09:05.720 --> 09:08.360
Still big steps.

09:08.360 --> 09:10.880
They fix this by the way, but they fix it by not patching

09:10.880 --> 09:12.760
and checkout, but by patching or upload artifact

09:12.760 --> 09:17.480
to ignore that files, which broke Python coverage.

09:17.480 --> 09:19.360
OK, getting a little bit more interesting.

09:19.360 --> 09:21.040
And we see the bug in this one.

09:21.040 --> 09:22.680
You'll notice that we are no longer

09:22.680 --> 09:25.000
doing environment expression injection.

09:25.000 --> 09:27.400
We're now forwarding by an environment variable.

09:27.400 --> 09:28.760
So there's no more rejection vulnerability there.

09:36.640 --> 09:37.440
OK.

09:37.440 --> 09:40.240
Like I said, good environment is one of those special variables

09:40.240 --> 09:42.560
to file, but it's just a file, nothing special.

09:42.560 --> 09:45.600
However, we can write multiple lines to it at once.

09:45.600 --> 09:47.600
So in this case, if a user or an attacker

09:47.600 --> 09:51.760
submits a title that matches that expression before,

09:51.760 --> 09:55.200
that expression because it uses the, I believe it's a p flag,

09:55.200 --> 09:57.440
it prints multiple times, once for each match.

09:57.440 --> 09:59.440
So in this case, we've injected two variables

09:59.440 --> 10:00.840
when we meant to only inject one.

10:00.840 --> 10:01.960
We've injected message equals two

10:01.960 --> 10:04.240
and also LD-free load equals hackme.so.

10:04.240 --> 10:06.000
And so now, if you can put right, if you have right access

10:06.000 --> 10:08.160
to a runner, even if you don't have execute access,

10:08.160 --> 10:10.000
you've turned your right access into execute access.

10:10.000 --> 10:11.240
Because LD-free load will run in front of anybody

10:11.240 --> 10:12.920
and nobody, they can execute it.

10:12.920 --> 10:15.240
So there you go.

10:15.240 --> 10:16.240
OK?

10:16.240 --> 10:19.000
Let's get a little bit more advanced.

10:19.000 --> 10:22.080
Get a backshins has services and APIs and actions

10:22.080 --> 10:23.360
for saving restoring caches.

10:23.360 --> 10:25.560
These are used in our critical for speeding up actions

10:25.560 --> 10:28.120
that pull on the things from public indices.

10:28.120 --> 10:29.480
These caches are key, and they can be restored

10:29.480 --> 10:30.760
based on partial key matches.

10:30.760 --> 10:32.880
So for example, if you have your us dependencies,

10:32.880 --> 10:34.400
you want to restore it from multiple different sources,

10:34.400 --> 10:38.880
if you've unfolded from multiple places.

10:38.880 --> 10:40.680
And the way it was told is when you have partial matches,

10:40.680 --> 10:43.600
this is a store is based on that partial match,

10:43.600 --> 10:45.720
but also sort of a privilege system of anything

10:45.720 --> 10:49.640
that's previously been landed in the upstream repo.

10:49.640 --> 10:51.560
So if you can poison that upstream cache,

10:51.560 --> 10:53.160
any downstream workflows that run

10:53.160 --> 10:56.640
will run with your poison cache.

10:56.640 --> 10:58.520
So here's the question, how does it get up?

10:58.520 --> 10:59.880
No, which branch?

10:59.880 --> 11:01.520
A cache frustration should come from.

11:01.520 --> 11:02.680
Well, the answer is, the branch engine

11:02.680 --> 11:03.840
is in a place of part of the cache key,

11:03.840 --> 11:05.680
and it's computed on the client side.

11:05.680 --> 11:08.440
How does get a backshins authenticate cache stores?

11:08.440 --> 11:10.760
It was authenticated with an actions runtime token,

11:10.760 --> 11:11.800
which is injected into the runner.

11:11.800 --> 11:14.040
Set it from the GitHub token.

11:14.040 --> 11:16.080
Combined, this is the perfect recipe for cache poisoning.

11:16.080 --> 11:18.840
We have the credential we need to inject cache entries,

11:18.840 --> 11:21.280
and we have a client side controlled cache prefix,

11:21.280 --> 11:24.720
which we can tell the actions cache service

11:24.720 --> 11:26.800
to cache with.

11:26.800 --> 11:28.200
There's no authenticated domain separation

11:28.200 --> 11:30.600
in other words between branches, which is hard to do,

11:30.600 --> 11:33.040
because you would need then a way to do a delegated authority

11:33.040 --> 11:35.600
between branches, meaning the branch

11:35.600 --> 11:37.600
can collaborate with others' caches.

11:37.600 --> 11:38.920
And all workflows in the repo

11:38.920 --> 11:41.000
that run with the repos permissions

11:41.000 --> 11:43.440
have that actions runtime token, which means

11:43.440 --> 11:44.840
that even a very, very weak workflow,

11:44.840 --> 11:49.720
when it has empty permissions, still has that cache token.

11:49.720 --> 11:51.640
And it's all for success, which means

11:51.640 --> 11:53.040
it's not run and evaluate runner-terry now,

11:53.040 --> 11:54.400
which means you have six hours to affect your cache

11:54.400 --> 11:56.000
poisoning attack.

11:56.000 --> 11:59.040
So this was kind of my spoiled by the previous session,

11:59.040 --> 12:01.440
but ultra-addicts is the perfect case study for this.

12:01.440 --> 12:03.680
Really popular machine learning vision model,

12:03.680 --> 12:05.600
68 million dollars from PIPI,

12:05.600 --> 12:06.960
and they have many CSCD operations

12:06.960 --> 12:08.920
that are intermediate by a body count.

12:11.120 --> 12:12.040
It's not the vulnerability.

12:14.240 --> 12:16.520
It's the exact same ones, it's our baby's step vulnerability.

12:16.520 --> 12:18.960
They inject directly into the shell context

12:18.960 --> 12:20.520
with the user control variable.

12:20.520 --> 12:22.160
This is happening with the pull request target trigger,

12:22.160 --> 12:23.600
which unlike a pull request,

12:23.600 --> 12:26.040
runs with the upstream repos permissions.

12:26.040 --> 12:29.040
So they've given this attacker upstream repo token permissions.

12:30.240 --> 12:33.360
The attacker sends a pull request with that title,

12:33.360 --> 12:37.160
which runs this payload, stills the cache token,

12:37.160 --> 12:41.840
and goes on to smash the cache with a bunch of entries,

12:41.840 --> 12:46.840
one of which eventually causes malicious PIPI upload.

12:46.840 --> 12:49.920
So what's cool about this is that they didn't steal,

12:49.920 --> 12:51.480
well, later on they steal, but at first,

12:51.480 --> 12:53.000
they didn't even steal the PIPI upload token.

12:53.000 --> 12:54.440
What they did was they poisoned the artifact

12:54.440 --> 12:56.280
that was used to produce the upload token.

12:56.280 --> 12:59.000
So this isn't visible from PIPI system.

13:00.200 --> 13:02.080
So they do this, right?

13:02.080 --> 13:04.640
Well, it's great is, and the risk is on fully on the eye

13:04.640 --> 13:06.640
with the push event, meaning that it was pretty hard to notice

13:06.640 --> 13:09.600
until someone actually knows that now we're on their system.

13:09.600 --> 13:11.440
But, you know, what's for what it's response,

13:11.440 --> 13:14.360
mission accomplished, they have deleted the,

13:14.360 --> 13:17.880
they have, you know, triage and everything.

13:17.880 --> 13:20.880
So I'll just several days later, it happens again.

13:20.880 --> 13:22.640
And the reason for this is that, even though

13:22.640 --> 13:24.800
they fixed the actual cache poisoning vulnerability

13:24.800 --> 13:27.480
and the permissions, the insecure trigger they use,

13:27.480 --> 13:28.920
they did not revoke their old credentials,

13:28.920 --> 13:30.920
and so the attacker just stole the old credentials,

13:30.920 --> 13:34.720
which they never revoked and did it again.

13:34.720 --> 13:36.960
So, after you've been owned on,

13:36.960 --> 13:38.760
get the actions, please revoke your credentials.

13:39.880 --> 13:42.200
Okay, I don't have enough time for these takeaways.

13:42.200 --> 13:43.200
Please look at the slides.

13:45.200 --> 13:46.680
Okay, now I actually want to talk about talk,

13:46.680 --> 13:48.040
which is hunting for bugs with this more.

13:48.040 --> 13:52.720
So, then at the time, you can do this yourself if you want,

13:52.720 --> 13:56.560
but here is this more, I'm gonna,

13:56.560 --> 13:57.400
run it without all my knowledge,

13:57.400 --> 13:58.800
because the Wi-Fi is kind of slow,

13:58.800 --> 14:01.240
and I'm gonna run it against the two repos

14:01.240 --> 14:02.960
that the actual attack was on.

14:02.960 --> 14:06.480
And it's pretty fast, and there we go.

14:08.680 --> 14:11.000
This is just every case where they,

14:11.000 --> 14:12.160
the attacker could have injected,

14:12.160 --> 14:16.920
the only need one of these, but, you know,

14:16.920 --> 14:17.760
it's not so good.

14:24.680 --> 14:26.000
Okay, technical details.

14:26.000 --> 14:27.720
There's more as a typical audit tool architecture.

14:27.720 --> 14:29.120
It has a preparation phase, an operation phase,

14:29.120 --> 14:31.360
an aggregation phase, and then the output is,

14:31.360 --> 14:34.080
like this rust, rusty, style, diagnostic.

14:34.080 --> 14:35.080
Where I'll tell you what's spanned,

14:35.080 --> 14:36.080
close to vulnerability.

14:38.280 --> 14:39.440
Individuals, this is more audits,

14:39.440 --> 14:40.880
our implementation of this audit trait,

14:42.080 --> 14:44.520
has pretty standard stuff, and then there's various ways

14:44.520 --> 14:45.360
you can define an audit.

14:45.360 --> 14:48.520
It can be over a workflow, composite action,

14:48.520 --> 14:49.920
or the individual steps are jobs,

14:49.920 --> 14:51.280
so then I'll work flow, if you only need that level

14:51.280 --> 14:52.360
of granularity.

14:52.360 --> 14:53.800
There's actually a new one to this audit raw,

14:53.800 --> 14:55.840
which can give the raw input to, as a strength,

14:55.840 --> 14:57.160
if you need to do just like basic.

14:57.160 --> 14:58.960
It's really, really, really basic rejects, matching.

15:01.560 --> 15:02.480
Oh, that's big enough, good.

15:02.480 --> 15:03.800
Okay, so that's an entire audit,

15:03.800 --> 15:05.680
it can be really small.

15:05.680 --> 15:06.640
This one's a secret inheritance audit,

15:06.640 --> 15:08.560
all it does, it looks for places

15:08.560 --> 15:10.320
where reusable work for use of secrets and herit,

15:10.320 --> 15:12.240
which means that inheritance the entire secrets context

15:12.240 --> 15:14.600
rather than being given a specific set of secrets,

15:14.600 --> 15:16.920
meaning it violates the principle of use authority,

15:18.040 --> 15:20.400
and then you can also do multiple locations

15:20.400 --> 15:21.240
for finding.

15:21.240 --> 15:23.200
So you can say, like, this step calls this action

15:23.200 --> 15:25.040
with this set of subfields,

15:25.040 --> 15:26.680
and that's why it produces such a nice sort

15:26.680 --> 15:29.440
of spanning representation on the command line.

15:29.440 --> 15:30.600
And yeah, if you want to contribute,

15:30.600 --> 15:32.800
these audits are good examples of things

15:32.800 --> 15:35.800
to start learning how to write this more audits.

15:35.800 --> 15:37.880
Some technical challenges.

15:37.880 --> 15:39.680
Like I said, it's all Yamohel under the hood,

15:39.680 --> 15:40.920
so one of the questions is, how do we model,

15:40.920 --> 15:44.800
it hubs complicated work flow and action contents,

15:44.800 --> 15:46.440
to extremely large JSON schema that's public,

15:46.440 --> 15:48.320
but it's very large and complicated,

15:48.320 --> 15:49.760
and Cojun's support is limited and rust

15:49.760 --> 15:51.200
for JSON schema.

15:51.200 --> 15:53.760
Solution is we have this GitHub Actions models trait,

15:53.760 --> 15:56.000
which has handwritten data models

15:56.000 --> 15:57.640
for every single part of GitHub Actions,

15:57.640 --> 15:59.120
which we then use generate those spans

15:59.120 --> 16:02.400
for Yamohel spanning back to the source.

16:02.400 --> 16:04.440
And then that follows the next question,

16:04.440 --> 16:06.880
which is, how do we turn these symbolic Yamohel contents

16:06.880 --> 16:08.680
like this step back into a span

16:08.680 --> 16:10.080
that we run into the user?

16:10.080 --> 16:12.440
An answer is, well, we couldn't with,

16:12.440 --> 16:14.680
there's no real span preserving Yamohel

16:14.680 --> 16:15.760
person to get for us,

16:15.760 --> 16:17.400
and also sort of Yamohel's deprecated,

16:17.400 --> 16:19.320
which still is, and we still have been on it,

16:19.320 --> 16:22.680
but Yamohel path, which comprises that abstract path,

16:22.680 --> 16:25.480
like, you know, job tests, steps, zero name,

16:25.480 --> 16:28.560
back into a source level syntax span

16:28.560 --> 16:29.640
for a pretty rendering.

16:31.040 --> 16:31.960
Okay, take away,

16:33.160 --> 16:37.120
stuff's complicated, has numerous security footguns,

16:37.120 --> 16:38.120
and those uses normal devs,

16:38.120 --> 16:39.640
and they should not be expecting to know these things.

16:39.640 --> 16:41.560
You shouldn't have to know that GitHub has no

16:41.560 --> 16:43.720
permission separation between branches

16:43.720 --> 16:45.360
to use caches securely,

16:46.520 --> 16:47.640
meaning that they're extra susceptible

16:47.640 --> 16:48.880
to insecurity faults.

16:50.120 --> 16:51.680
Moreover, offensive security research

16:51.680 --> 16:54.560
and GitHub Actions is still pretty new as a field.

16:54.560 --> 16:57.760
Really, the first visible public efforts

16:57.760 --> 17:00.040
into this stuff started around 2021,

17:00.040 --> 17:02.240
and new attacks and techniques are still being discovered.

17:02.240 --> 17:03.680
For example, the cache poisoning attack

17:03.680 --> 17:05.280
was just last summer.

17:05.280 --> 17:07.360
And so, even though I've talked about some of this stuff,

17:07.360 --> 17:09.000
it's not anywhere close to the end all,

17:09.000 --> 17:11.880
or well-being the close to the end all of action security.

17:13.320 --> 17:14.440
And, yes, of that.

17:15.720 --> 17:17.000
It's also simultaneously kind of,

17:17.000 --> 17:19.120
because it's just Yamohel,

17:19.120 --> 17:20.640
and also very difficult to analyze,

17:20.640 --> 17:23.200
because it's extremely dynamic in puts like contacts,

17:23.200 --> 17:24.880
which can be loaded with pretty much anything,

17:24.880 --> 17:27.440
including dynamic matrices that get loaded at runtime.

17:27.440 --> 17:29.360
So those kinds of things are very difficult,

17:29.360 --> 17:31.360
to analyze, and we try our best.

17:32.440 --> 17:34.680
As part of that, you know, we detect many security pitfalls,

17:34.680 --> 17:36.320
but not with perfect fidelity.

17:36.320 --> 17:38.120
And this is, in part, because of design choices,

17:38.120 --> 17:40.600
for example, favoring offline audit and we're possible,

17:40.600 --> 17:42.360
but also because of that fundamental dynamic movement,

17:42.360 --> 17:44.720
sort of models, normal computer of psychoanalysis.

17:44.720 --> 17:45.640
You can't do certain things,

17:45.640 --> 17:47.840
because the program is dynamic in your static.

17:49.080 --> 17:50.360
Okay, so I spent running all that,

17:50.360 --> 17:52.640
so I could have some time for questions.

17:52.640 --> 17:54.240
Thank you all very much for listening.

17:54.240 --> 17:55.520
If you want slides up here.

17:55.520 --> 17:57.640
Thank you all very much for listening.

17:57.640 --> 17:59.640
If you want slides up here.

17:59.640 --> 18:01.320
All right.

18:01.320 --> 18:02.800
Yes.

18:02.800 --> 18:04.000
Thank you very much, though.

18:04.000 --> 18:07.120
I have a quick question to down,

18:07.120 --> 18:09.920
where to say, self-indulgence of a long line,

18:09.920 --> 18:11.560
but I have one of the more of the five lines,

18:11.560 --> 18:14.480
so I want to open to make this in my five lines.

18:14.480 --> 18:17.000
Any force within this inside line,

18:17.000 --> 18:21.520
where does one put an action that we're going to check?

18:21.520 --> 18:22.520
Do real flow itself?

18:22.520 --> 18:23.520
Yes.

18:23.520 --> 18:25.720
So the question was, can I use this in my pipeline?

18:25.720 --> 18:26.520
And the answer is yes.

18:26.520 --> 18:28.320
So I showed the human output.

18:28.320 --> 18:29.960
There's also a seraph output that it integrates

18:29.960 --> 18:30.960
directly into GitHub.

18:30.960 --> 18:34.920
And so you can see on GitHub a UI render of these findings.

18:34.920 --> 18:37.640
OK, then, we'll see right in your pipeline.

18:37.640 --> 18:38.680
Yes, exactly.

18:38.680 --> 18:40.680
Yeah.

18:40.680 --> 18:41.480
Yeah.

18:41.480 --> 18:42.520
Yeah, on Guru uses it.

18:42.520 --> 18:43.840
So you can use it to humber as a reference point

18:43.840 --> 18:45.760
for using it and see it inside.

18:45.760 --> 18:47.360
Yes.

18:47.360 --> 18:48.960
Sort of a variation on the same question,

18:48.960 --> 18:50.280
sorry about that.

18:50.280 --> 18:54.520
Is it possible to read right above, right?

18:54.520 --> 18:55.720
The same kind of article.

18:55.720 --> 18:58.720
There's a code queue, which is GitHub own.

18:58.720 --> 18:59.720
Yeah.

18:59.720 --> 19:00.720
Yeah.

19:00.720 --> 19:02.280
So the question was, can we rewrite the same kind of rules

19:02.280 --> 19:03.560
using GitHub's code cool feature?

19:03.560 --> 19:05.120
And answers they have.

19:05.120 --> 19:07.920
GitHub two weeks ago introduced beta support

19:07.920 --> 19:10.280
for GitHub actions all the time with code URL.

19:10.280 --> 19:12.440
And I will say this, because I wrote this tool.

19:12.440 --> 19:15.960
CodeQL is a much better fundamental system than what I wrote.

19:15.960 --> 19:18.440
So if you want a system that is fundamentally built

19:18.440 --> 19:20.000
or set a analysis, check it out.

19:20.000 --> 19:21.360
The downside is that it's codeQL.

19:21.360 --> 19:21.720
It's big.

19:21.720 --> 19:22.520
It's complicated.

19:22.520 --> 19:23.000
It's integrated.

19:23.000 --> 19:25.720
So there's some trade-off there.

19:25.720 --> 19:26.720
Yes.

19:26.720 --> 19:28.840
If here, it could be called C9.

19:28.840 --> 19:30.000
That's what the search phrase is.

19:30.000 --> 19:32.440
If it is given by one of the problem,

19:32.440 --> 19:34.600
the same word, it's not in any way.

19:34.600 --> 19:34.920
Yeah.

19:34.920 --> 19:37.400
The question was, is GitHub CI similar?

19:37.400 --> 19:38.600
And answers, I have no idea.

19:38.600 --> 19:40.800
Ha, ha, ha, ha, ha, ha.

19:40.800 --> 19:41.800
Maybe.

19:41.800 --> 19:43.520
I would love it if someone looked in sent me patches

19:43.520 --> 19:46.520
to support GitHub CI.

19:46.520 --> 19:47.520
Yes?

19:47.520 --> 19:52.240
I mean, GitHub actions as well as the GitHub provided

19:52.240 --> 19:57.840
actions are subject to regular updates.

19:57.840 --> 20:01.840
How do you play on keeping up with this thing?

20:01.840 --> 20:04.440
Yeah, so that's a question.

20:04.440 --> 20:06.040
The question is, how do we keep up to date with the latest

20:06.040 --> 20:09.920
changes to, for example, the official actions?

20:09.920 --> 20:12.520
My long-term plan is to have a static representation

20:12.520 --> 20:15.600
that we can upload via an HTTP, put it on HTTP

20:15.600 --> 20:17.920
and server somewhere, how to static API to pull it down.

20:17.920 --> 20:21.120
So if the default posture of an action changes,

20:21.120 --> 20:22.960
clients that don't want to update this more itself,

20:22.960 --> 20:25.760
can fetch that, and basically update the rules.

20:25.760 --> 20:27.200
Currently, it's baked into the binary.

20:27.200 --> 20:30.000
So currently, if actions changes to me fundamentally,

20:30.000 --> 20:33.480
which they haven't really yet, I have to send a new release.

20:33.480 --> 20:34.320
So it's probably going to get it.

20:34.320 --> 20:36.560
Yeah.

20:36.560 --> 20:37.080
Yes.

20:37.080 --> 20:37.760
Please contribute.

20:37.760 --> 20:42.400
All right.

20:42.400 --> 20:43.560
Thank you very much.

20:43.560 --> 20:44.560
Yeah.

