Fork Bomb
Technical explanation of a Linux fork bomb (bash fork() DoS attack). Learn how the :(){ :|:& };: fork bomb works, why it exhausts system resources, and how to prevent it using ulimit, PAM, and process limits"
- Understanding
:(){ :|:& };: fork()bomb code
The :() – Defined the function called :. This function accepts no arguments. The syntax for bash function is as follows
foo(){
arg1=$1
arg2=$2
echo 'Bar..'
#do_something on $arg argument
}
fork() bomb is defined as follows
:|:– Next it will call itself using programming technique called recursion and pipes the output to another call of the function:. The worst part is function get called two times to bomb your system.&– Puts the function call in the background so child cannot die at all and start eating system resources.;– Terminate the function definition.:– Call (run) the function aka set the fork() bomb.
:(){
:|:&
};:
Fork Bomb (one-liner)
:(){ :|:& };:
Here is more human readable code for a fork bomb
forkbomb() {
forkbomb | forkbomb &
};forkbomb
Properly configured Linux / UNIX box should not go down when fork() bomb sets off.
Preventing fork bomb on Linux
Please don’t set ulimit numbers too low. This will prevent you from working on your system.
To protect our system against Fork Bombs, we can cap the processes owned by a certain user, thus blocking process creation at that cap.
Using the nix utility called ulimit, we can set the maximum number of processes that a user can execute in the system, using the flag -u. By setting this value to an appropriate (lower) value, we can cap the process creation for a user, ensuring we can never be fork bombed by that user.
Now run fork bomb again
:(){ :|:& };:
You just avoided fork bomb on Linux. Run the following pgrep command to see the current threads limit
pgrep -wcu $USER
Preventing Bash Fork Bombs
For Linux distros using systemd, the methods above may result in the opening of a lot of processes. However, the system won’t crash and after some time it automatically closes all processes.
This is because systemd creates a cgroup for each user which sets limits on system resources such as the total number of processes, RAM usage, etc.
It’s a more modern layer of resource limiting than ulimit which uses the getrlimit() system call.
Let’s see the current and maximum number of processes and threads that are allowed within our current cgroup
$ systemctl status user-$UID.slice
● user-1000.slice - User Slice of UID 1000
Loaded: loaded
Drop-In: /usr/lib//system/user-.slice.d
└─10-defaults.conf
Active: active since Sat 2025-12-20 21:03:04 CET; 1 month 9 days ago
Docs: man:user@.service(5)
Tasks: 18 (limit: 15315)
Memory: 1.3G
CPU: 5h 30min 12.899s
CGroup: /user.slice/user-1000.slice
├─session-2.scope
│ ├─ 587 /bin/login -p --
│ └─1699 -bash
├─session-5610.scope
│ ├─209774 SCREEN -S weechat
│ ├─209775 /bin/bash
│ └─209779 weechat
├─session-5619.scope
│ └─209985 ./eggdrop
├─session-8691.scope
│ ├─289193 "nginx: master process nginx -c /etc/nginx/nginx.conf"
│ ├─388242 "nginx: worker process"
│ └─388243 "nginx: worker process"
├─session-9803.scope
│ ├─394528 "sshd: <username> [priv]"
│ ├─394534 "sshd: <username>@pts/0"
│ ├─394535 -bash
│ ├─394539 systemctl status user-1000.slice
│ └─394540 pager
└─user@1000.service
├─app.slice
│ └─gpg-agent.service
│ └─281807 /usr/bin/gpg-agent --supervised
└─init.scope
├─1683 /lib// --user
└─1684 "(sd-pam)"
By default, the total number of tasks that allows for each user is usually 33% of the system-wide total.
Let’s find out the system-wide total
$ sysctl kernel.threads-max
kernel.threads-max = 186057
To crash a system running on ``, we need to reduce the limit on the number of processes
-
Here’s how we can do this for
version 239and later:systemctl [--runtime] set-property user-$UID.slice TasksMax=2500 -
Here, we’re setting the maximum number of tasks to
2500. Running the fork bomb after this change will crash the system.
Alternatively, for systemd version 238 and earlier, the user default is set via UserTasksMax= in the /etc//logind.conf directory
vim /etc//logind.conf
Mitigation Techniques
Fork bombs are not unique to Bash - Many other languages can implement them.
-
There are mainly two reasons a fork bomb can happen:
- a software bug that, at some point, creates too many processes, crashing the computer
- a malicious hacker attack, where the hacker finds a way to run their code on the victim’s system and implements a fork bomb in order to perform a denial of service on that computer
-
We can prevent a Bash fork bomb from crashing our system by limiting how many processes our user can run.
-
We can achieve this by editing the
/etc/security/limits.conffile with root permissions and setting the maximum number of processes for the user:<username> hard nproc <number_of_processes> -
Now the question would be, what’s a good number of processes to set as a limit?
A simple way to know a good number is to open as many programs as we’d normally use simultaneously and then count them in the terminal
ps aux -L | cut --delimiter=" " --fields=1 | sort | uniq --count | sort --numeric-sort | tail --lines=1
We should then take that number and multiply it by two to be conservative. We do this because setting a number too low might bring up issues during our day-to-day use.
After that, we can finish editing the /etc/security/limits.conf file and finally reboot the system to apply the new configuration.
How to prevent fork bombs
As everything is related to processes, you just have to limit them. And the maximum processes that can run through a signed-in user can be checked through a given command
$ ulimit -u
23206
- My current setup is around
23206kand any linux user would have at least around10k, which is much more than enough.
So what you have to do is limit those background processes to around 5K, which should be plenty for most users
ulimit -S -u 5000
But this would only be effective for specific users. You can also apply this to the group by editing the /etc/security/limits.conf file
vim /etc/security/limits.conf
-
For example, I want to apply this to all users who are in wheel group, so I’d be adding the following lines at the end of the config file:
@wheel hard nproc 5000 -
Whereas for any specific user (
<username> in your case) it would be this:<username> hard nproc 5000