Humanoid:TakeDamage() Allows Health to exceed MaxHealth

Directly assigning a number larger than the Humanoid’s MaxHealth will correctly cap the Humanoid’s Health at the MaxHealth.

This can by bypassed by providing a negative number value to Humanoid:TakeDamage() that is large(small?) enough to cause the Humanoid’s health. A considerable amount of games are client authoritative as to which Humanoid’s they apply damage to, and what number value, making this an easily exploitable flaw.

A simple reproduction in a Script in StarterCharacterScripts:

local humanoid = script.Parent:WaitForChild('Humanoid')

print(humanoid.Health)

humanoid:TakeDamage(-humanoid.MaxHealth * 2)

print(humanoid.Health)
4 Likes

This is patchable by developers.

It’s also an intended feature as it’s on the old Developer Wiki.

You could patch this out by running a server-side check, i.e.

Health.Changed:Connect(function(health)
if Health > Humanoid.MaxHealth then
Humanoid.Health = Humanoid.MaxHealth
end
end)

I’m more than certain this doesn’t replicate as you have to fire a RemoteEvent in order to change the Humanoid’s health on the server - it would explain why the “God” command used in Admin exploits don’t work. In the off-chance it does, you can use the above server check to keep the player’s health below the threshold.

Images comparing what the client sees vs what the server sees when the client changes their health locally

Server:


Client:

After server damages Client with “exploited” Health value:

I am a bit disappointed that TakeDamage() caps the lowest possible health at 0 instead of allowing it to go negative.

Negative values healing the humanoid is expected behavior; allowing for the possibility of skyrocketing the health beyond the maxhealth is not.

This is from a currently in use combat system I am fully replacing for someone;

	DealDamage = function ()

	local takeDamage = sabers.Global.createRemote("Event","TakeDamage",sabers.Global.remotes)
	
	takeDamage.OnServerEvent:connect(function (player, humanoid, amount)

		local function death_tag(playerGetKOs, playerHumnanoid)
	
			local creator = Instance.new("ObjectValue")
			creator.Name = "creator"
			creator.Value = playerGetKOs
			creator.Parent = playerHumnanoid
	
		end

		if humanoid.Health > 0 and humanoid.Health - amount <= 0 then
			death_tag(player, humanoid)
		end
		humanoid:TakeDamage(amount)
	end)
end,

I’ve helped rewrite quite a few gun and sword systems for people now and the great majority of have fully client authoritative application of damage, just like this one.

This behaves totally opposite direct applications to the health value, which caps at maxhealth always.

Leaving such a large game breaking flaw for possibility of exploitation is an easy way to ensure exploitation.

Although this is most likely unintended behaviour, keep in mind that client changes to health will not be replicated to the server or other clients, so clients setting their own health wouldn’t mean much.

Nonetheless, a bug is a bug.

1 Like

If a developer relies on client-reliant damage, then that’s bad design on their part.
Health should always be handled on the server, with the optional visual damage for the client doing the damage.

I don’t really think this is a bug because it’s been in Roblox as long as I can remember and has been used in healthkits created by Roblox to my knowledge.

It’s not a “gamebreaking bug.” If it breaks your game, you’re programming your system incorrectly. Trusting the client for handling health, or anything else, is a bad idea.

If anything, it makes it easier to code health bonuses that don’t require manually setting the MaxHealth to 200 while keeping the starting health to 100, which would make the healthbar above players appear to be at only 50% of their total health.

Even if a client were, for some reason, able to change their health to 3000 by using the TakeDamage() approach, then as soon as they take damage by the server, their health will change to what their health actually is.

I.e. exploiter changes their health to 4000 when their health is at 5. Exploiter takes damage by something on the server that does 10 damage, and instead of having 3990 health, they die, due to their health only actually being 5.

2 Likes

I would prefer this stay a feature for ease of creating an “overheal” mechanic. This is not gamebreaking and cannot be abused by exploiters, however changing it may very well be gamebreaking and remove a useful quirk of the engine (much like the removal of negative walkspeed).


These games are programmed incorrectly, and any exploits the developers discover with their damage system are their own fault. Client sided health changes do not replicate automatically, and if the client can ask the server to change their own health indiscriminately, then somebody has failed to implement basic remote security through sanity checking.

1 Like