The better question is why would you not use prepared statements, give me a good reason...
I'm wondering if it's safe to use a Session variable in SQL statements.
No.
Are the users able to modify the session variables?
Not directly but consider this
$_SESSION['value'] = $_POST['value'];
Has the user modified the session? No, is it safe. No.
So you may think I will never do that, but as an application grows complex what will you know that every single value you put in the session has never been touched by user data.
Consider this:
class foo{
function bar($value){
$db->query('select * from table where value ='.$value]);
}
}
$foo->bar($_SESSION['value']);
Now say some other file does what I mentioned above (with session), you can't see that from the baddy written class's code. You also can't see the Session code from looking at the class. So just by looking at one or the other you have no way to know if what you are doing is safe. Maybe you will be vigilant when you write it, what about months, years latter. Will you remember?
Prepared statements work because you can see this right at the point of failure, because they don't rely on good coding in other places to make up for their bad coding.
Now assume you want to reuse the function bar with the data directly from the Post array because well it's a waste to store it in the session. So you change it, but you have no way to know if it's safe without opening the class, another example of Point of failure.
What happens if we use prepared statements on these? what do we lose? a few keystrokes.
No say someone manages to exploits your baddy written class what do we lose, well depending on what your site does you could lose a whole lot. Maybe you have no data of value, maybe you have social security numbers. Who knows, but it wont be good. At the very least you'll lose any trust your users have in you.
So I ask again, why wouldn't you just use prepared statements on them.
And I mean this in the nicest of ways. It's just not worth it.
By the way this
$db->prepare('SELECT Name FROM Users WHERE Years = :Years')
is a prepared statement, which is the correct way. While this
$db->prepare("SELECT Name FROM Users WHERE Years = $Years")
is not safe no matter how you do it.
So if you are asking if the code you are using in the answer is safe. Then yes it looks that way. But if you are asking if this is safe:
$db->query("SELECT Name FROM Users WHERE Years = {$_SESSION['Years']}")
Then I would say no, never.
You can put basically anything you want in a prepared statement and have it be safe, that is the whole point of it. Because you're asking, I am pretty sure you don't really understand the basics of SQLInjection attacks yet. Because there is a big difference between a SQL Statement, and a Prepared Statement.
There are many of tutorials on videos on the web about this but here as a previous answer that explains it a bit.
How does SQL-injection work and how do I protect against it